Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2020, Linaro Limited
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/slab.h>
0006 #include <linux/soc/qcom/apr.h>
0007 #include <sound/soc.h>
0008 #include <sound/soc-dai.h>
0009 #include <sound/pcm.h>
0010 #include <sound/pcm_params.h>
0011 #include <dt-bindings/soc/qcom,gpr.h>
0012 #include "q6apm.h"
0013 #include "audioreach.h"
0014 
0015 /* SubGraph Config */
0016 struct apm_sub_graph_data {
0017     struct apm_sub_graph_cfg sub_graph_cfg;
0018     struct apm_prop_data perf_data;
0019     struct apm_sg_prop_id_perf_mode perf;
0020     struct apm_prop_data dir_data;
0021     struct apm_sg_prop_id_direction dir;
0022     struct apm_prop_data sid_data;
0023     struct apm_sg_prop_id_scenario_id sid;
0024 
0025 } __packed;
0026 
0027 #define APM_SUB_GRAPH_CFG_NPROP 3
0028 
0029 struct apm_sub_graph_params  {
0030     struct apm_module_param_data param_data;
0031     uint32_t num_sub_graphs;
0032     struct apm_sub_graph_data sg_cfg[];
0033 } __packed;
0034 
0035 #define APM_SUB_GRAPH_PSIZE(p, n) ALIGN(struct_size(p, sg_cfg, n), 8)
0036 
0037 /* container config */
0038 struct apm_container_obj  {
0039     struct apm_container_cfg container_cfg;
0040     /* Capability ID list */
0041     struct apm_prop_data cap_data;
0042     uint32_t num_capability_id;
0043     uint32_t capability_id;
0044 
0045     /* Container graph Position */
0046     struct apm_prop_data pos_data;
0047     struct apm_cont_prop_id_graph_pos pos;
0048 
0049     /* Container Stack size */
0050     struct apm_prop_data stack_data;
0051     struct apm_cont_prop_id_stack_size stack;
0052 
0053     /* Container proc domain id */
0054     struct apm_prop_data domain_data;
0055     struct apm_cont_prop_id_domain domain;
0056 } __packed;
0057 
0058 struct apm_container_params  {
0059     struct apm_module_param_data param_data;
0060     uint32_t num_containers;
0061     struct apm_container_obj cont_obj[];
0062 } __packed;
0063 
0064 #define APM_CONTAINER_PSIZE(p, n) ALIGN(struct_size(p, cont_obj, n), 8)
0065 
0066 /* Module List config */
0067 struct apm_mod_list_obj {
0068     /* Modules list cfg */
0069     uint32_t sub_graph_id;
0070     uint32_t container_id;
0071     uint32_t num_modules;
0072     struct apm_module_obj mod_cfg[];
0073 } __packed;
0074 
0075 #define APM_MOD_LIST_OBJ_PSIZE(p, n) struct_size(p, mod_cfg, n)
0076 
0077 struct apm_module_list_params {
0078     struct apm_module_param_data param_data;
0079     uint32_t num_modules_list;
0080     /* Module list config array */
0081     struct apm_mod_list_obj mod_list_obj[];
0082 } __packed;
0083 
0084 
0085 /* Module Properties */
0086 struct apm_mod_prop_obj {
0087     u32 instance_id;
0088     u32 num_props;
0089     struct apm_prop_data prop_data_1;
0090     struct apm_module_prop_id_port_info prop_id_port;
0091 } __packed;
0092 
0093 struct apm_prop_list_params {
0094     struct apm_module_param_data param_data;
0095     u32 num_modules_prop_cfg;
0096     struct apm_mod_prop_obj mod_prop_obj[];
0097 
0098 } __packed;
0099 
0100 #define APM_MOD_PROP_PSIZE(p, n) ALIGN(struct_size(p, mod_prop_obj, n), 8)
0101 
0102 /* Module Connections */
0103 struct apm_mod_conn_list_params {
0104     struct apm_module_param_data param_data;
0105     u32 num_connections;
0106     struct apm_module_conn_obj conn_obj[];
0107 
0108 } __packed;
0109 
0110 #define APM_MOD_CONN_PSIZE(p, n) ALIGN(struct_size(p, conn_obj, n), 8)
0111 
0112 struct apm_graph_open_params {
0113     struct apm_cmd_header *cmd_header;
0114     struct apm_sub_graph_params *sg_data;
0115     struct apm_container_params *cont_data;
0116     struct apm_module_list_params *mod_list_data;
0117     struct apm_prop_list_params *mod_prop_data;
0118     struct apm_mod_conn_list_params *mod_conn_list_data;
0119 } __packed;
0120 
0121 struct apm_pcm_module_media_fmt_cmd {
0122     struct apm_module_param_data param_data;
0123     struct param_id_pcm_output_format_cfg header;
0124     struct payload_pcm_output_format_cfg media_cfg;
0125 } __packed;
0126 
0127 struct apm_rd_shmem_module_config_cmd {
0128     struct apm_module_param_data param_data;
0129     struct param_id_rd_sh_mem_cfg cfg;
0130 } __packed;
0131 
0132 struct apm_sh_module_media_fmt_cmd {
0133     struct media_format header;
0134     struct payload_media_fmt_pcm cfg;
0135 } __packed;
0136 
0137 #define APM_SHMEM_FMT_CFG_PSIZE(ch) ALIGN( \
0138                 sizeof(struct apm_sh_module_media_fmt_cmd) + \
0139                 ch * sizeof(uint8_t), 8)
0140 
0141 /* num of channels as argument */
0142 #define APM_PCM_MODULE_FMT_CMD_PSIZE(ch) ALIGN( \
0143                 sizeof(struct apm_pcm_module_media_fmt_cmd) + \
0144                 ch * sizeof(uint8_t), 8)
0145 
0146 #define APM_PCM_OUT_FMT_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4)
0147 
0148 struct apm_i2s_module_intf_cfg {
0149     struct apm_module_param_data param_data;
0150     struct param_id_i2s_intf_cfg cfg;
0151 } __packed;
0152 
0153 #define APM_I2S_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_i2s_module_intf_cfg), 8)
0154 
0155 struct apm_module_hw_ep_mf_cfg {
0156     struct apm_module_param_data param_data;
0157     struct param_id_hw_ep_mf mf;
0158 } __packed;
0159 
0160 #define APM_HW_EP_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_mf_cfg), 8)
0161 
0162 struct apm_module_frame_size_factor_cfg {
0163     struct apm_module_param_data param_data;
0164     uint32_t frame_size_factor;
0165 } __packed;
0166 
0167 #define APM_FS_CFG_PSIZE ALIGN(sizeof(struct apm_module_frame_size_factor_cfg), 8)
0168 
0169 struct apm_module_hw_ep_power_mode_cfg {
0170     struct apm_module_param_data param_data;
0171     struct param_id_hw_ep_power_mode_cfg power_mode;
0172 } __packed;
0173 
0174 #define APM_HW_EP_PMODE_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_power_mode_cfg), 8)
0175 
0176 struct apm_module_hw_ep_dma_data_align_cfg {
0177     struct apm_module_param_data param_data;
0178     struct param_id_hw_ep_dma_data_align align;
0179 } __packed;
0180 
0181 #define APM_HW_EP_DALIGN_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_dma_data_align_cfg), 8)
0182 
0183 struct apm_gain_module_cfg {
0184     struct apm_module_param_data param_data;
0185     struct param_id_gain_cfg gain_cfg;
0186 } __packed;
0187 
0188 #define APM_GAIN_CFG_PSIZE ALIGN(sizeof(struct apm_gain_module_cfg), 8)
0189 
0190 struct apm_codec_dma_module_intf_cfg {
0191     struct apm_module_param_data param_data;
0192     struct param_id_codec_dma_intf_cfg cfg;
0193 } __packed;
0194 
0195 #define APM_CDMA_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_codec_dma_module_intf_cfg), 8)
0196 
0197 static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token,
0198                     uint32_t src_port, uint32_t dest_port, bool has_cmd_hdr)
0199 {
0200     struct gpr_pkt *pkt;
0201     void *p;
0202     int pkt_size = GPR_HDR_SIZE + payload_size;
0203 
0204     if (has_cmd_hdr)
0205         pkt_size += APM_CMD_HDR_SIZE;
0206 
0207     p = kzalloc(pkt_size, GFP_KERNEL);
0208     if (!p)
0209         return ERR_PTR(-ENOMEM);
0210 
0211     pkt = p;
0212     pkt->hdr.version = GPR_PKT_VER;
0213     pkt->hdr.hdr_size = GPR_PKT_HEADER_WORD_SIZE;
0214     pkt->hdr.pkt_size = pkt_size;
0215     pkt->hdr.dest_port = dest_port;
0216     pkt->hdr.src_port = src_port;
0217 
0218     pkt->hdr.dest_domain = GPR_DOMAIN_ID_ADSP;
0219     pkt->hdr.src_domain = GPR_DOMAIN_ID_APPS;
0220     pkt->hdr.token = token;
0221     pkt->hdr.opcode = opcode;
0222 
0223     if (has_cmd_hdr) {
0224         struct apm_cmd_header *cmd_header;
0225 
0226         p = p + GPR_HDR_SIZE;
0227         cmd_header = p;
0228         cmd_header->payload_size = payload_size;
0229     }
0230 
0231     return pkt;
0232 }
0233 
0234 void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token,
0235                uint32_t src_port, uint32_t dest_port)
0236 {
0237     return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, false);
0238 }
0239 EXPORT_SYMBOL_GPL(audioreach_alloc_pkt);
0240 
0241 void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port)
0242 {
0243     return __audioreach_alloc_pkt(pkt_size, opcode, token, src_port, APM_MODULE_INSTANCE_ID,
0244                       false);
0245 }
0246 EXPORT_SYMBOL_GPL(audioreach_alloc_apm_pkt);
0247 
0248 void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, uint32_t token,
0249                    uint32_t src_port, uint32_t dest_port)
0250 {
0251     return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, true);
0252 }
0253 EXPORT_SYMBOL_GPL(audioreach_alloc_cmd_pkt);
0254 
0255 void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token)
0256 {
0257     return __audioreach_alloc_pkt(pkt_size, opcode, token, GPR_APM_MODULE_IID,
0258                        APM_MODULE_INSTANCE_ID, true);
0259 }
0260 EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt);
0261 
0262 static void apm_populate_container_config(struct apm_container_obj *cfg,
0263                       struct audioreach_container *cont)
0264 {
0265 
0266     /* Container Config */
0267     cfg->container_cfg.container_id = cont->container_id;
0268     cfg->container_cfg.num_prop = 4;
0269 
0270     /* Capability list */
0271     cfg->cap_data.prop_id = APM_CONTAINER_PROP_ID_CAPABILITY_LIST;
0272     cfg->cap_data.prop_size = APM_CONTAINER_PROP_ID_CAPABILITY_SIZE;
0273     cfg->num_capability_id = 1;
0274     cfg->capability_id = cont->capability_id;
0275 
0276     /* Graph Position */
0277     cfg->pos_data.prop_id = APM_CONTAINER_PROP_ID_GRAPH_POS;
0278     cfg->pos_data.prop_size = sizeof(struct apm_cont_prop_id_graph_pos);
0279     cfg->pos.graph_pos = cont->graph_pos;
0280 
0281     /* Stack size */
0282     cfg->stack_data.prop_id = APM_CONTAINER_PROP_ID_STACK_SIZE;
0283     cfg->stack_data.prop_size = sizeof(struct apm_cont_prop_id_stack_size);
0284     cfg->stack.stack_size = cont->stack_size;
0285 
0286     /* Proc domain */
0287     cfg->domain_data.prop_id = APM_CONTAINER_PROP_ID_PROC_DOMAIN;
0288     cfg->domain_data.prop_size = sizeof(struct apm_cont_prop_id_domain);
0289     cfg->domain.proc_domain = cont->proc_domain;
0290 }
0291 
0292 static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg,
0293                       struct audioreach_sub_graph *sg)
0294 {
0295     cfg->sub_graph_cfg.sub_graph_id = sg->sub_graph_id;
0296     cfg->sub_graph_cfg.num_sub_graph_prop = APM_SUB_GRAPH_CFG_NPROP;
0297 
0298     /* Perf Mode */
0299     cfg->perf_data.prop_id = APM_SUB_GRAPH_PROP_ID_PERF_MODE;
0300     cfg->perf_data.prop_size = APM_SG_PROP_ID_PERF_MODE_SIZE;
0301     cfg->perf.perf_mode = sg->perf_mode;
0302 
0303     /* Direction */
0304     cfg->dir_data.prop_id = APM_SUB_GRAPH_PROP_ID_DIRECTION;
0305     cfg->dir_data.prop_size = APM_SG_PROP_ID_DIR_SIZE;
0306     cfg->dir.direction = sg->direction;
0307 
0308     /* Scenario ID */
0309     cfg->sid_data.prop_id = APM_SUB_GRAPH_PROP_ID_SCENARIO_ID;
0310     cfg->sid_data.prop_size = APM_SG_PROP_ID_SID_SIZE;
0311     cfg->sid.scenario_id = sg->scenario_id;
0312 }
0313 
0314 static void apm_populate_connection_obj(struct apm_module_conn_obj *obj,
0315                     struct audioreach_module *module)
0316 {
0317     obj->src_mod_inst_id = module->src_mod_inst_id;
0318     obj->src_mod_op_port_id = module->src_mod_op_port_id;
0319     obj->dst_mod_inst_id = module->instance_id;
0320     obj->dst_mod_ip_port_id = module->in_port;
0321 }
0322 
0323 static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
0324                      struct audioreach_module *module)
0325 {
0326 
0327     obj->instance_id = module->instance_id;
0328     obj->num_props = 1;
0329     obj->prop_data_1.prop_id = APM_MODULE_PROP_ID_PORT_INFO;
0330     obj->prop_data_1.prop_size = APM_MODULE_PROP_ID_PORT_INFO_SZ;
0331     obj->prop_id_port.max_ip_port = module->max_ip_port;
0332     obj->prop_id_port.max_op_port = module->max_op_port;
0333 }
0334 
0335 struct audioreach_module *audioreach_get_container_last_module(
0336                             struct audioreach_container *container)
0337 {
0338     struct audioreach_module *module;
0339 
0340     list_for_each_entry(module, &container->modules_list, node) {
0341         if (module->dst_mod_inst_id == 0)
0342             return module;
0343     }
0344 
0345     return NULL;
0346 }
0347 EXPORT_SYMBOL_GPL(audioreach_get_container_last_module);
0348 
0349 static bool is_module_in_container(struct audioreach_container *container, int module_iid)
0350 {
0351     struct audioreach_module *module;
0352 
0353     list_for_each_entry(module, &container->modules_list, node) {
0354         if (module->instance_id == module_iid)
0355             return true;
0356     }
0357 
0358     return false;
0359 }
0360 
0361 struct audioreach_module *audioreach_get_container_first_module(
0362                             struct audioreach_container *container)
0363 {
0364     struct audioreach_module *module;
0365 
0366     /* get the first module from both connected or un-connected containers */
0367     list_for_each_entry(module, &container->modules_list, node) {
0368         if (module->src_mod_inst_id == 0 ||
0369             !is_module_in_container(container, module->src_mod_inst_id))
0370             return module;
0371     }
0372     return NULL;
0373 }
0374 EXPORT_SYMBOL_GPL(audioreach_get_container_first_module);
0375 
0376 struct audioreach_module *audioreach_get_container_next_module(
0377                         struct audioreach_container *container,
0378                         struct audioreach_module *module)
0379 {
0380     int nmodule_iid = module->dst_mod_inst_id;
0381     struct audioreach_module *nmodule;
0382 
0383     list_for_each_entry(nmodule, &container->modules_list, node) {
0384         if (nmodule->instance_id == nmodule_iid)
0385             return nmodule;
0386     }
0387 
0388     return NULL;
0389 }
0390 EXPORT_SYMBOL_GPL(audioreach_get_container_next_module);
0391 
0392 static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
0393                      struct audioreach_container *container,
0394                      int sub_graph_id)
0395 {
0396     struct audioreach_module *module;
0397     int i;
0398 
0399     obj->sub_graph_id = sub_graph_id;
0400     obj->container_id = container->container_id;
0401     obj->num_modules = container->num_modules;
0402     i = 0;
0403     list_for_each_container_module(module, container) {
0404         obj->mod_cfg[i].module_id = module->module_id;
0405         obj->mod_cfg[i].instance_id = module->instance_id;
0406         i++;
0407     }
0408 }
0409 
0410 static void audioreach_populate_graph(struct apm_graph_open_params *open,
0411                       struct list_head *sg_list,
0412                       int num_sub_graphs)
0413 {
0414     struct apm_mod_conn_list_params *mc_data = open->mod_conn_list_data;
0415     struct apm_module_list_params *ml_data = open->mod_list_data;
0416     struct apm_prop_list_params *mp_data = open->mod_prop_data;
0417     struct apm_container_params *c_data = open->cont_data;
0418     struct apm_sub_graph_params *sg_data = open->sg_data;
0419     int ncontainer = 0, nmodule = 0, nconn = 0;
0420     struct apm_mod_prop_obj *module_prop_obj;
0421     struct audioreach_container *container;
0422     struct apm_module_conn_obj *conn_obj;
0423     struct audioreach_module *module;
0424     struct audioreach_sub_graph *sg;
0425     struct apm_container_obj *cobj;
0426     struct apm_mod_list_obj *mlobj;
0427     int i = 0;
0428 
0429     mlobj = &ml_data->mod_list_obj[0];
0430 
0431     list_for_each_entry(sg, sg_list, node) {
0432         struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++];
0433 
0434         apm_populate_sub_graph_config(sg_cfg, sg);
0435 
0436         list_for_each_entry(container, &sg->container_list, node) {
0437             cobj = &c_data->cont_obj[ncontainer];
0438 
0439             apm_populate_container_config(cobj, container);
0440             apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id);
0441 
0442             list_for_each_container_module(module, container) {
0443                 uint32_t src_mod_inst_id;
0444 
0445                 src_mod_inst_id = module->src_mod_inst_id;
0446 
0447                 module_prop_obj = &mp_data->mod_prop_obj[nmodule];
0448                 apm_populate_module_prop_obj(module_prop_obj, module);
0449 
0450                 if (src_mod_inst_id) {
0451                     conn_obj = &mc_data->conn_obj[nconn];
0452                     apm_populate_connection_obj(conn_obj, module);
0453                     nconn++;
0454                 }
0455 
0456                 nmodule++;
0457             }
0458             mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
0459 
0460             ncontainer++;
0461         }
0462     }
0463 }
0464 
0465 void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id)
0466 {
0467     int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz;
0468     struct apm_module_param_data  *param_data;
0469     struct apm_container_params *cont_params;
0470     struct audioreach_container *container;
0471     struct apm_sub_graph_params *sg_params;
0472     struct apm_mod_conn_list_params *mcon;
0473     struct apm_graph_open_params params;
0474     struct apm_prop_list_params *mprop;
0475     struct audioreach_module *module;
0476     struct audioreach_sub_graph *sgs;
0477     struct apm_mod_list_obj *mlobj;
0478     int num_modules_per_list;
0479     int num_connections = 0;
0480     int num_containers = 0;
0481     int num_sub_graphs = 0;
0482     int num_modules = 0;
0483     int num_modules_list;
0484     struct gpr_pkt *pkt;
0485     void *p;
0486 
0487     list_for_each_entry(sgs, sg_list, node) {
0488         num_sub_graphs++;
0489         list_for_each_entry(container, &sgs->container_list, node) {
0490             num_containers++;
0491             num_modules += container->num_modules;
0492             list_for_each_container_module(module, container) {
0493                 if (module->src_mod_inst_id)
0494                     num_connections++;
0495             }
0496         }
0497     }
0498 
0499     num_modules_list = num_containers;
0500     num_modules_per_list = num_modules/num_containers;
0501     sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs);
0502     cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers);
0503     ml_sz = ALIGN(sizeof(struct apm_module_list_params) +
0504         num_modules_list * APM_MOD_LIST_OBJ_PSIZE(mlobj,  num_modules_per_list), 8);
0505     mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules);
0506     mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections);
0507 
0508     payload_size = sg_sz + cont_sz + ml_sz + mp_sz + mc_sz;
0509     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0);
0510     if (IS_ERR(pkt))
0511         return pkt;
0512 
0513     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0514 
0515     /* SubGraph */
0516     params.sg_data = p;
0517     param_data = &params.sg_data->param_data;
0518     param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
0519     param_data->param_id = APM_PARAM_ID_SUB_GRAPH_CONFIG;
0520     param_data->param_size = sg_sz - APM_MODULE_PARAM_DATA_SIZE;
0521     params.sg_data->num_sub_graphs = num_sub_graphs;
0522     p += sg_sz;
0523 
0524     /* Container */
0525     params.cont_data = p;
0526     param_data = &params.cont_data->param_data;
0527     param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
0528     param_data->param_id = APM_PARAM_ID_CONTAINER_CONFIG;
0529     param_data->param_size = cont_sz - APM_MODULE_PARAM_DATA_SIZE;
0530     params.cont_data->num_containers = num_containers;
0531     p += cont_sz;
0532 
0533     /* Module List*/
0534     params.mod_list_data = p;
0535     param_data = &params.mod_list_data->param_data;
0536     param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
0537     param_data->param_id = APM_PARAM_ID_MODULE_LIST;
0538     param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE;
0539     params.mod_list_data->num_modules_list = num_sub_graphs;
0540     p += ml_sz;
0541 
0542     /* Module Properties */
0543     params.mod_prop_data = p;
0544     param_data = &params.mod_prop_data->param_data;
0545     param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
0546     param_data->param_id = APM_PARAM_ID_MODULE_PROP;
0547     param_data->param_size = mp_sz - APM_MODULE_PARAM_DATA_SIZE;
0548     params.mod_prop_data->num_modules_prop_cfg = num_modules;
0549     p += mp_sz;
0550 
0551     /* Module Connections */
0552     params.mod_conn_list_data = p;
0553     param_data = &params.mod_conn_list_data->param_data;
0554     param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
0555     param_data->param_id = APM_PARAM_ID_MODULE_CONN;
0556     param_data->param_size = mc_sz - APM_MODULE_PARAM_DATA_SIZE;
0557     params.mod_conn_list_data->num_connections = num_connections;
0558     p += mc_sz;
0559 
0560     audioreach_populate_graph(&params, sg_list, num_sub_graphs);
0561 
0562     return pkt;
0563 }
0564 EXPORT_SYMBOL_GPL(audioreach_alloc_graph_pkt);
0565 
0566 int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev,
0567                  struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock,
0568                  gpr_port_t *port, wait_queue_head_t *cmd_wait,
0569                  struct gpr_pkt *pkt, uint32_t rsp_opcode)
0570 {
0571 
0572     struct gpr_hdr *hdr = &pkt->hdr;
0573     int rc;
0574 
0575     mutex_lock(cmd_lock);
0576     result->opcode = 0;
0577     result->status = 0;
0578 
0579     if (port)
0580         rc = gpr_send_port_pkt(port, pkt);
0581     else if (gdev)
0582         rc = gpr_send_pkt(gdev, pkt);
0583     else
0584         rc = -EINVAL;
0585 
0586     if (rc < 0)
0587         goto err;
0588 
0589     if (rsp_opcode)
0590         rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode) ||
0591                     (result->opcode == rsp_opcode), 5 * HZ);
0592     else
0593         rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 5 * HZ);
0594 
0595     if (!rc) {
0596         dev_err(dev, "CMD timeout for [%x] opcode\n", hdr->opcode);
0597         rc = -ETIMEDOUT;
0598     } else if (result->status > 0) {
0599         dev_err(dev, "DSP returned error[%x] %x\n", hdr->opcode, result->status);
0600         rc = -EINVAL;
0601     } else {
0602         /* DSP successfully finished the command */
0603         rc = 0;
0604     }
0605 
0606 err:
0607     mutex_unlock(cmd_lock);
0608     return rc;
0609 }
0610 EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync);
0611 
0612 int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, struct gpr_pkt *pkt,
0613                    uint32_t rsp_opcode)
0614 {
0615 
0616     return audioreach_send_cmd_sync(graph->dev, NULL,  &graph->result, &graph->lock,
0617                     graph->port, &graph->cmd_wait, pkt, rsp_opcode);
0618 }
0619 EXPORT_SYMBOL_GPL(audioreach_graph_send_cmd_sync);
0620 
0621 /* LPASS Codec DMA port Module Media Format Setup */
0622 static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
0623                          struct audioreach_module *module,
0624                          struct audioreach_module_config *cfg)
0625 {
0626     struct apm_codec_dma_module_intf_cfg *intf_cfg;
0627     struct apm_module_frame_size_factor_cfg *fs_cfg;
0628     struct apm_module_hw_ep_power_mode_cfg *pm_cfg;
0629     struct apm_module_param_data *param_data;
0630     struct apm_module_hw_ep_mf_cfg *hw_cfg;
0631     int ic_sz, ep_sz, fs_sz, pm_sz, dl_sz;
0632     int rc, payload_size;
0633     struct gpr_pkt *pkt;
0634     void *p;
0635 
0636     ic_sz = APM_CDMA_INTF_CFG_PSIZE;
0637     ep_sz = APM_HW_EP_CFG_PSIZE;
0638     fs_sz = APM_FS_CFG_PSIZE;
0639     pm_sz = APM_HW_EP_PMODE_CFG_PSIZE;
0640     dl_sz = 0;
0641 
0642     payload_size = ic_sz + ep_sz + fs_sz + pm_sz + dl_sz;
0643 
0644     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0645     if (IS_ERR(pkt))
0646         return PTR_ERR(pkt);
0647 
0648     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0649 
0650     hw_cfg = p;
0651     param_data = &hw_cfg->param_data;
0652     param_data->module_instance_id = module->instance_id;
0653     param_data->error_code = 0;
0654     param_data->param_id = PARAM_ID_HW_EP_MF_CFG;
0655     param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE;
0656 
0657     hw_cfg->mf.sample_rate = cfg->sample_rate;
0658     hw_cfg->mf.bit_width = cfg->bit_width;
0659     hw_cfg->mf.num_channels = cfg->num_channels;
0660     hw_cfg->mf.data_format = module->data_format;
0661     p += ep_sz;
0662 
0663     fs_cfg = p;
0664     param_data = &fs_cfg->param_data;
0665     param_data->module_instance_id = module->instance_id;
0666     param_data->error_code = 0;
0667     param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR;
0668     param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE;
0669     fs_cfg->frame_size_factor = 1;
0670     p += fs_sz;
0671 
0672     intf_cfg = p;
0673     param_data = &intf_cfg->param_data;
0674     param_data->module_instance_id = module->instance_id;
0675     param_data->error_code = 0;
0676     param_data->param_id = PARAM_ID_CODEC_DMA_INTF_CFG;
0677     param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE;
0678 
0679     intf_cfg->cfg.lpaif_type = module->hw_interface_type;
0680     intf_cfg->cfg.intf_index = module->hw_interface_idx;
0681     intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1;
0682     p += ic_sz;
0683 
0684     pm_cfg = p;
0685     param_data = &pm_cfg->param_data;
0686     param_data->module_instance_id = module->instance_id;
0687     param_data->error_code = 0;
0688     param_data->param_id = PARAM_ID_HW_EP_POWER_MODE_CFG;
0689     param_data->param_size = pm_sz - APM_MODULE_PARAM_DATA_SIZE;
0690     pm_cfg->power_mode.power_mode = 0;
0691 
0692     rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
0693 
0694     kfree(pkt);
0695 
0696     return rc;
0697 }
0698 
0699 static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
0700                        struct audioreach_module *module,
0701                        struct audioreach_module_config *cfg)
0702 {
0703     struct apm_module_frame_size_factor_cfg *fs_cfg;
0704     struct apm_module_param_data *param_data;
0705     struct apm_i2s_module_intf_cfg *intf_cfg;
0706     struct apm_module_hw_ep_mf_cfg *hw_cfg;
0707     int ic_sz, ep_sz, fs_sz;
0708     int rc, payload_size;
0709     struct gpr_pkt *pkt;
0710     void *p;
0711 
0712     ic_sz = APM_I2S_INTF_CFG_PSIZE;
0713     ep_sz = APM_HW_EP_CFG_PSIZE;
0714     fs_sz = APM_FS_CFG_PSIZE;
0715 
0716     payload_size = ic_sz + ep_sz + fs_sz;
0717 
0718     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0719     if (IS_ERR(pkt))
0720         return PTR_ERR(pkt);
0721 
0722     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0723     intf_cfg = p;
0724 
0725     param_data = &intf_cfg->param_data;
0726     param_data->module_instance_id = module->instance_id;
0727     param_data->error_code = 0;
0728     param_data->param_id = PARAM_ID_I2S_INTF_CFG;
0729     param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE;
0730 
0731     intf_cfg->cfg.intf_idx = module->hw_interface_idx;
0732     intf_cfg->cfg.sd_line_idx = module->sd_line_idx;
0733 
0734     switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0735     case SND_SOC_DAIFMT_BP_FP:
0736         intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL;
0737         break;
0738     case SND_SOC_DAIFMT_BC_FC:
0739         /* CPU is slave */
0740         intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL;
0741         break;
0742     default:
0743         break;
0744     }
0745 
0746     p += ic_sz;
0747     hw_cfg = p;
0748     param_data = &hw_cfg->param_data;
0749     param_data->module_instance_id = module->instance_id;
0750     param_data->error_code = 0;
0751     param_data->param_id = PARAM_ID_HW_EP_MF_CFG;
0752     param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE;
0753 
0754     hw_cfg->mf.sample_rate = cfg->sample_rate;
0755     hw_cfg->mf.bit_width = cfg->bit_width;
0756     hw_cfg->mf.num_channels = cfg->num_channels;
0757     hw_cfg->mf.data_format = module->data_format;
0758 
0759     p += ep_sz;
0760     fs_cfg = p;
0761     param_data = &fs_cfg->param_data;
0762     param_data->module_instance_id = module->instance_id;
0763     param_data->error_code = 0;
0764     param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR;
0765     param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE;
0766     fs_cfg->frame_size_factor = 1;
0767 
0768     rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
0769 
0770     kfree(pkt);
0771 
0772     return rc;
0773 }
0774 
0775 static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
0776                            struct audioreach_module *module)
0777 {
0778     struct apm_module_param_data *param_data;
0779     struct data_logging_config *cfg;
0780     int rc, payload_size;
0781     struct gpr_pkt *pkt;
0782     void *p;
0783 
0784     payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
0785     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0786     if (IS_ERR(pkt))
0787         return PTR_ERR(pkt);
0788 
0789     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0790 
0791     param_data = p;
0792     param_data->module_instance_id = module->instance_id;
0793     param_data->error_code = 0;
0794     param_data->param_id = PARAM_ID_DATA_LOGGING_CONFIG;
0795     param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
0796 
0797     p = p + APM_MODULE_PARAM_DATA_SIZE;
0798     cfg = p;
0799     cfg->log_code = module->log_code;
0800     cfg->log_tap_point_id = module->log_tap_point_id;
0801     cfg->mode = module->log_mode;
0802 
0803     rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
0804 
0805     kfree(pkt);
0806 
0807     return rc;
0808 }
0809 
0810 static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
0811                        struct audioreach_module *module,
0812                        struct audioreach_module_config *mcfg)
0813 {
0814     struct payload_pcm_output_format_cfg *media_cfg;
0815     uint32_t num_channels = mcfg->num_channels;
0816     struct apm_pcm_module_media_fmt_cmd *cfg;
0817     struct apm_module_param_data *param_data;
0818     int rc, payload_size;
0819     struct gpr_pkt *pkt;
0820 
0821     if (num_channels > 2) {
0822         dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
0823         return -EINVAL;
0824     }
0825 
0826     payload_size = APM_PCM_MODULE_FMT_CMD_PSIZE(num_channels);
0827 
0828     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0829     if (IS_ERR(pkt))
0830         return PTR_ERR(pkt);
0831 
0832     cfg = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0833 
0834     param_data = &cfg->param_data;
0835     param_data->module_instance_id = module->instance_id;
0836     param_data->error_code = 0;
0837     param_data->param_id = PARAM_ID_PCM_OUTPUT_FORMAT_CFG;
0838     param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
0839 
0840     cfg->header.data_format = DATA_FORMAT_FIXED_POINT;
0841     cfg->header.fmt_id = MEDIA_FMT_ID_PCM;
0842     cfg->header.payload_size = APM_PCM_OUT_FMT_CFG_PSIZE(media_cfg, num_channels);
0843 
0844     media_cfg = &cfg->media_cfg;
0845     media_cfg->alignment = PCM_LSB_ALIGNED;
0846     media_cfg->bit_width = mcfg->bit_width;
0847     media_cfg->endianness = PCM_LITTLE_ENDIAN;
0848     media_cfg->interleaved = module->interleave_type;
0849     media_cfg->num_channels = mcfg->num_channels;
0850     media_cfg->q_factor = mcfg->bit_width - 1;
0851     media_cfg->bits_per_sample = mcfg->bit_width;
0852 
0853     if (num_channels == 1) {
0854         media_cfg->channel_mapping[0] = PCM_CHANNEL_L;
0855     } else if (num_channels == 2) {
0856         media_cfg->channel_mapping[0] = PCM_CHANNEL_L;
0857         media_cfg->channel_mapping[1] = PCM_CHANNEL_R;
0858 
0859     }
0860 
0861     rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
0862 
0863     kfree(pkt);
0864 
0865     return rc;
0866 }
0867 
0868 static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
0869                          struct audioreach_module *module,
0870                          struct audioreach_module_config *mcfg)
0871 {
0872     uint32_t num_channels = mcfg->num_channels;
0873     struct apm_module_param_data *param_data;
0874     struct payload_media_fmt_pcm *cfg;
0875     struct media_format *header;
0876     int rc, payload_size;
0877     struct gpr_pkt *pkt;
0878     void *p;
0879 
0880     if (num_channels > 2) {
0881         dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
0882         return -EINVAL;
0883     }
0884 
0885     payload_size = APM_SHMEM_FMT_CFG_PSIZE(num_channels) + APM_MODULE_PARAM_DATA_SIZE;
0886 
0887     pkt = audioreach_alloc_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0,
0888                      graph->port->id, module->instance_id);
0889     if (IS_ERR(pkt))
0890         return PTR_ERR(pkt);
0891 
0892     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0893 
0894     param_data = p;
0895     param_data->module_instance_id = module->instance_id;
0896     param_data->error_code = 0;
0897     param_data->param_id = PARAM_ID_MEDIA_FORMAT;
0898     param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
0899     p = p + APM_MODULE_PARAM_DATA_SIZE;
0900 
0901     header = p;
0902     header->data_format = DATA_FORMAT_FIXED_POINT;
0903     header->fmt_id = MEDIA_FMT_ID_PCM;
0904     header->payload_size = payload_size - sizeof(*header);
0905 
0906     p = p + sizeof(*header);
0907     cfg = p;
0908     cfg->sample_rate = mcfg->sample_rate;
0909     cfg->bit_width = mcfg->bit_width;
0910     cfg->alignment = PCM_LSB_ALIGNED;
0911     cfg->bits_per_sample = mcfg->bit_width;
0912     cfg->q_factor = mcfg->bit_width - 1;
0913     cfg->endianness = PCM_LITTLE_ENDIAN;
0914     cfg->num_channels = mcfg->num_channels;
0915 
0916     if (mcfg->num_channels == 1) {
0917         cfg->channel_mapping[0] =  PCM_CHANNEL_L;
0918     } else if (num_channels == 2) {
0919         cfg->channel_mapping[0] =  PCM_CHANNEL_L;
0920         cfg->channel_mapping[1] =  PCM_CHANNEL_R;
0921     }
0922 
0923     rc = audioreach_graph_send_cmd_sync(graph, pkt, 0);
0924 
0925     kfree(pkt);
0926 
0927     return rc;
0928 }
0929 
0930 int audioreach_gain_set_vol_ctrl(struct q6apm *apm, struct audioreach_module *module, int vol)
0931 {
0932     struct param_id_vol_ctrl_master_gain *cfg;
0933     struct apm_module_param_data *param_data;
0934     int rc, payload_size;
0935     struct gpr_pkt *pkt;
0936     void *p;
0937 
0938     payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
0939     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0940     if (IS_ERR(pkt))
0941         return PTR_ERR(pkt);
0942 
0943     p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0944 
0945     param_data = p;
0946     param_data->module_instance_id = module->instance_id;
0947     param_data->error_code = 0;
0948     param_data->param_id = PARAM_ID_VOL_CTRL_MASTER_GAIN;
0949     param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
0950 
0951     p = p + APM_MODULE_PARAM_DATA_SIZE;
0952     cfg = p;
0953     cfg->master_gain =  vol;
0954     rc = q6apm_send_cmd_sync(apm, pkt, 0);
0955 
0956     kfree(pkt);
0957 
0958     return rc;
0959 }
0960 EXPORT_SYMBOL_GPL(audioreach_gain_set_vol_ctrl);
0961 
0962 static int audioreach_gain_set(struct q6apm_graph *graph, struct audioreach_module *module)
0963 {
0964     struct apm_module_param_data *param_data;
0965     struct apm_gain_module_cfg *cfg;
0966     int rc, payload_size;
0967     struct gpr_pkt *pkt;
0968 
0969     payload_size = APM_GAIN_CFG_PSIZE;
0970     pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
0971     if (IS_ERR(pkt))
0972         return PTR_ERR(pkt);
0973 
0974     cfg = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
0975 
0976     param_data = &cfg->param_data;
0977     param_data->module_instance_id = module->instance_id;
0978     param_data->error_code = 0;
0979     param_data->param_id = APM_PARAM_ID_GAIN;
0980     param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
0981 
0982     cfg->gain_cfg.gain = module->gain;
0983 
0984     rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
0985 
0986     kfree(pkt);
0987 
0988     return rc;
0989 }
0990 
0991 int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_module *module,
0992                 struct audioreach_module_config *cfg)
0993 {
0994     int rc;
0995 
0996     switch (module->module_id) {
0997     case MODULE_ID_DATA_LOGGING:
0998         rc = audioreach_logging_set_media_format(graph, module);
0999         break;
1000     case MODULE_ID_PCM_DEC:
1001     case MODULE_ID_PCM_ENC:
1002     case MODULE_ID_PCM_CNV:
1003         rc = audioreach_pcm_set_media_format(graph, module, cfg);
1004         break;
1005     case MODULE_ID_I2S_SOURCE:
1006     case MODULE_ID_I2S_SINK:
1007         rc = audioreach_i2s_set_media_format(graph, module, cfg);
1008         break;
1009     case MODULE_ID_WR_SHARED_MEM_EP:
1010         rc = audioreach_shmem_set_media_format(graph, module, cfg);
1011         break;
1012     case MODULE_ID_GAIN:
1013         rc = audioreach_gain_set(graph, module);
1014         break;
1015     case MODULE_ID_CODEC_DMA_SINK:
1016     case MODULE_ID_CODEC_DMA_SOURCE:
1017         rc = audioreach_codec_dma_set_media_format(graph, module, cfg);
1018         break;
1019     default:
1020         rc = 0;
1021     }
1022 
1023     return rc;
1024 }
1025 EXPORT_SYMBOL_GPL(audioreach_set_media_format);
1026 
1027 void audioreach_graph_free_buf(struct q6apm_graph *graph)
1028 {
1029     struct audioreach_graph_data *port;
1030 
1031     mutex_lock(&graph->lock);
1032     port = &graph->rx_data;
1033     port->num_periods = 0;
1034     kfree(port->buf);
1035     port->buf = NULL;
1036 
1037     port = &graph->tx_data;
1038     port->num_periods = 0;
1039     kfree(port->buf);
1040     port->buf = NULL;
1041     mutex_unlock(&graph->lock);
1042 }
1043 EXPORT_SYMBOL_GPL(audioreach_graph_free_buf);
1044 
1045 int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, size_t period_sz,
1046                   unsigned int periods, bool is_contiguous)
1047 {
1048     struct apm_shared_map_region_payload *mregions;
1049     struct apm_cmd_shared_mem_map_regions *cmd;
1050     uint32_t num_regions, buf_sz, payload_size;
1051     struct audioreach_graph_data *data;
1052     struct gpr_pkt *pkt;
1053     void *p;
1054     int rc, i;
1055 
1056     if (dir == SNDRV_PCM_STREAM_PLAYBACK)
1057         data = &graph->rx_data;
1058     else
1059         data = &graph->tx_data;
1060 
1061     if (is_contiguous) {
1062         num_regions = 1;
1063         buf_sz = period_sz * periods;
1064     } else {
1065         buf_sz = period_sz;
1066         num_regions = periods;
1067     }
1068 
1069     /* DSP expects size should be aligned to 4K */
1070     buf_sz = ALIGN(buf_sz, 4096);
1071 
1072     payload_size = sizeof(*cmd) + (sizeof(*mregions) * num_regions);
1073 
1074     pkt = audioreach_alloc_apm_pkt(payload_size, APM_CMD_SHARED_MEM_MAP_REGIONS, dir,
1075                      graph->port->id);
1076     if (IS_ERR(pkt))
1077         return PTR_ERR(pkt);
1078 
1079     p = (void *)pkt + GPR_HDR_SIZE;
1080     cmd = p;
1081     cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL;
1082     cmd->num_regions = num_regions;
1083 
1084     cmd->property_flag = 0x0;
1085 
1086     mregions = p + sizeof(*cmd);
1087 
1088     mutex_lock(&graph->lock);
1089 
1090     for (i = 0; i < num_regions; i++) {
1091         struct audio_buffer *ab;
1092 
1093         ab = &data->buf[i];
1094         mregions->shm_addr_lsw = lower_32_bits(ab->phys);
1095         mregions->shm_addr_msw = upper_32_bits(ab->phys);
1096         mregions->mem_size_bytes = buf_sz;
1097         ++mregions;
1098     }
1099     mutex_unlock(&graph->lock);
1100 
1101     rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
1102 
1103     kfree(pkt);
1104 
1105     return rc;
1106 }
1107 EXPORT_SYMBOL_GPL(audioreach_map_memory_regions);
1108 
1109 int audioreach_shared_memory_send_eos(struct q6apm_graph *graph)
1110 {
1111     struct data_cmd_wr_sh_mem_ep_eos *eos;
1112     struct gpr_pkt *pkt;
1113     int rc = 0, iid;
1114 
1115     iid = q6apm_graph_get_rx_shmem_module_iid(graph);
1116     pkt = audioreach_alloc_cmd_pkt(sizeof(*eos), DATA_CMD_WR_SH_MEM_EP_EOS, 0,
1117                        graph->port->id, iid);
1118     if (IS_ERR(pkt))
1119         return PTR_ERR(pkt);
1120 
1121     eos = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
1122 
1123     eos->policy = WR_SH_MEM_EP_EOS_POLICY_LAST;
1124 
1125     rc = gpr_send_port_pkt(graph->port, pkt);
1126     kfree(pkt);
1127 
1128     return rc;
1129 }
1130 EXPORT_SYMBOL_GPL(audioreach_shared_memory_send_eos);