162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sst_ipc.c - Intel SST Driver for audio engine 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008-14 Intel Corporation 662306a36Sopenharmony_ci * Authors: Vinod Koul <vinod.koul@intel.com> 762306a36Sopenharmony_ci * Harsha Priya <priya.harsha@intel.com> 862306a36Sopenharmony_ci * Dharageswari R <dharageswari.r@intel.com> 962306a36Sopenharmony_ci * KP Jeeja <jeeja.kp@intel.com> 1062306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/firmware.h> 1662306a36Sopenharmony_ci#include <linux/sched.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <sound/core.h> 1962306a36Sopenharmony_ci#include <sound/pcm.h> 2062306a36Sopenharmony_ci#include <sound/soc.h> 2162306a36Sopenharmony_ci#include <sound/compress_driver.h> 2262306a36Sopenharmony_ci#include <asm/intel-mid.h> 2362306a36Sopenharmony_ci#include <asm/platform_sst_audio.h> 2462306a36Sopenharmony_ci#include "../sst-mfld-platform.h" 2562306a36Sopenharmony_ci#include "sst.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct sst_block *sst_create_block(struct intel_sst_drv *ctx, 2862306a36Sopenharmony_ci u32 msg_id, u32 drv_id) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct sst_block *msg; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 3362306a36Sopenharmony_ci msg = kzalloc(sizeof(*msg), GFP_KERNEL); 3462306a36Sopenharmony_ci if (!msg) 3562306a36Sopenharmony_ci return NULL; 3662306a36Sopenharmony_ci msg->condition = false; 3762306a36Sopenharmony_ci msg->on = true; 3862306a36Sopenharmony_ci msg->msg_id = msg_id; 3962306a36Sopenharmony_ci msg->drv_id = drv_id; 4062306a36Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 4162306a36Sopenharmony_ci list_add_tail(&msg->node, &ctx->block_list); 4262306a36Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return msg; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * while handling the interrupts, we need to check for message status and 4962306a36Sopenharmony_ci * then if we are blocking for a message 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * here we are unblocking the blocked ones, this is based on id we have 5262306a36Sopenharmony_ci * passed and search that for block threads. 5362306a36Sopenharmony_ci * We will not find block in two cases 5462306a36Sopenharmony_ci * a) when its small message and block in not there, so silently ignore 5562306a36Sopenharmony_ci * them 5662306a36Sopenharmony_ci * b) when we are actually not able to find the block (bug perhaps) 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Since we have bit of small messages we can spam kernel log with err 5962306a36Sopenharmony_ci * print on above so need to keep as debug prints which should be enabled 6062306a36Sopenharmony_ci * via dynamic debug while debugging IPC issues 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ciint sst_wake_up_block(struct intel_sst_drv *ctx, int result, 6362306a36Sopenharmony_ci u32 drv_id, u32 ipc, void *data, u32 size) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct sst_block *block; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 7062306a36Sopenharmony_ci list_for_each_entry(block, &ctx->block_list, node) { 7162306a36Sopenharmony_ci dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id, 7262306a36Sopenharmony_ci block->drv_id); 7362306a36Sopenharmony_ci if (block->msg_id == ipc && block->drv_id == drv_id) { 7462306a36Sopenharmony_ci dev_dbg(ctx->dev, "free up the block\n"); 7562306a36Sopenharmony_ci block->ret_code = result; 7662306a36Sopenharmony_ci block->data = data; 7762306a36Sopenharmony_ci block->size = size; 7862306a36Sopenharmony_ci block->condition = true; 7962306a36Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 8062306a36Sopenharmony_ci wake_up(&ctx->wait_queue); 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 8562306a36Sopenharmony_ci dev_dbg(ctx->dev, 8662306a36Sopenharmony_ci "Block not found or a response received for a short msg for ipc %d, drv_id %d\n", 8762306a36Sopenharmony_ci ipc, drv_id); 8862306a36Sopenharmony_ci return -EINVAL; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct sst_block *block, *__block; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 9662306a36Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 9762306a36Sopenharmony_ci list_for_each_entry_safe(block, __block, &ctx->block_list, node) { 9862306a36Sopenharmony_ci if (block == freed) { 9962306a36Sopenharmony_ci pr_debug("pvt_id freed --> %d\n", freed->drv_id); 10062306a36Sopenharmony_ci /* toggle the index position of pvt_id */ 10162306a36Sopenharmony_ci list_del(&freed->node); 10262306a36Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 10362306a36Sopenharmony_ci kfree(freed->data); 10462306a36Sopenharmony_ci freed->data = NULL; 10562306a36Sopenharmony_ci kfree(freed); 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 11062306a36Sopenharmony_ci dev_err(ctx->dev, "block is already freed!!!\n"); 11162306a36Sopenharmony_ci return -EINVAL; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciint sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, 11562306a36Sopenharmony_ci struct ipc_post *ipc_msg, bool sync) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct ipc_post *msg = ipc_msg; 11862306a36Sopenharmony_ci union ipc_header_mrfld header; 11962306a36Sopenharmony_ci unsigned int loop_count = 0; 12062306a36Sopenharmony_ci int retval = 0; 12162306a36Sopenharmony_ci unsigned long irq_flags; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync); 12462306a36Sopenharmony_ci spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); 12562306a36Sopenharmony_ci header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); 12662306a36Sopenharmony_ci if (sync) { 12762306a36Sopenharmony_ci while (header.p.header_high.part.busy) { 12862306a36Sopenharmony_ci if (loop_count > 25) { 12962306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, 13062306a36Sopenharmony_ci "sst: Busy wait failed, can't send this msg\n"); 13162306a36Sopenharmony_ci retval = -EBUSY; 13262306a36Sopenharmony_ci goto out; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci cpu_relax(); 13562306a36Sopenharmony_ci loop_count++; 13662306a36Sopenharmony_ci header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } else { 13962306a36Sopenharmony_ci if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { 14062306a36Sopenharmony_ci /* queue is empty, nothing to send */ 14162306a36Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 14262306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, 14362306a36Sopenharmony_ci "Empty msg queue... NO Action\n"); 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (header.p.header_high.part.busy) { 14862306a36Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 14962306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n"); 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* copy msg from list */ 15462306a36Sopenharmony_ci msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, 15562306a36Sopenharmony_ci struct ipc_post, node); 15662306a36Sopenharmony_ci list_del(&msg->node); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n", 15962306a36Sopenharmony_ci msg->mrfld_header.p.header_high.full); 16062306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n", 16162306a36Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (msg->mrfld_header.p.header_high.part.large) 16462306a36Sopenharmony_ci memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, 16562306a36Sopenharmony_ci msg->mailbox_data, 16662306a36Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciout: 17162306a36Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 17262306a36Sopenharmony_ci kfree(msg->mailbox_data); 17362306a36Sopenharmony_ci kfree(msg); 17462306a36Sopenharmony_ci return retval; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci union interrupt_reg_mrfld isr; 18062306a36Sopenharmony_ci union interrupt_reg_mrfld imr; 18162306a36Sopenharmony_ci union ipc_header_mrfld clear_ipc; 18262306a36Sopenharmony_ci unsigned long irq_flags; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); 18562306a36Sopenharmony_ci imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); 18662306a36Sopenharmony_ci isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* write 1 to clear*/ 18962306a36Sopenharmony_ci isr.part.busy_interrupt = 1; 19062306a36Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Set IA done bit */ 19362306a36Sopenharmony_ci clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci clear_ipc.p.header_high.part.busy = 0; 19662306a36Sopenharmony_ci clear_ipc.p.header_high.part.done = 1; 19762306a36Sopenharmony_ci clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS; 19862306a36Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full); 19962306a36Sopenharmony_ci /* un mask busy interrupt */ 20062306a36Sopenharmony_ci imr.part.busy_interrupt = 0; 20162306a36Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); 20262306a36Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * process_fw_init - process the FW init msg 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * @msg: IPC message mailbox data from FW 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * This function processes the FW init msg from FW 21262306a36Sopenharmony_ci * marks FW state and prints debug info of loaded FW 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic void process_fw_init(struct intel_sst_drv *sst_drv_ctx, 21562306a36Sopenharmony_ci void *msg) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ipc_header_fw_init *init = 21862306a36Sopenharmony_ci (struct ipc_header_fw_init *)msg; 21962306a36Sopenharmony_ci int retval = 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n"); 22262306a36Sopenharmony_ci if (init->result) { 22362306a36Sopenharmony_ci sst_set_fw_state_locked(sst_drv_ctx, SST_RESET); 22462306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n", 22562306a36Sopenharmony_ci init->result); 22662306a36Sopenharmony_ci retval = init->result; 22762306a36Sopenharmony_ci goto ret; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci if (memcmp(&sst_drv_ctx->fw_version, &init->fw_version, 23062306a36Sopenharmony_ci sizeof(init->fw_version))) 23162306a36Sopenharmony_ci dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", 23262306a36Sopenharmony_ci init->fw_version.type, init->fw_version.major, 23362306a36Sopenharmony_ci init->fw_version.minor, init->fw_version.build); 23462306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", 23562306a36Sopenharmony_ci init->build_info.date, init->build_info.time); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Save FW version */ 23862306a36Sopenharmony_ci sst_drv_ctx->fw_version.type = init->fw_version.type; 23962306a36Sopenharmony_ci sst_drv_ctx->fw_version.major = init->fw_version.major; 24062306a36Sopenharmony_ci sst_drv_ctx->fw_version.minor = init->fw_version.minor; 24162306a36Sopenharmony_ci sst_drv_ctx->fw_version.build = init->fw_version.build; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciret: 24462306a36Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, 24862306a36Sopenharmony_ci struct ipc_post *msg) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci u32 msg_id; 25162306a36Sopenharmony_ci int str_id; 25262306a36Sopenharmony_ci u32 data_size, i; 25362306a36Sopenharmony_ci void *data_offset; 25462306a36Sopenharmony_ci struct stream_info *stream; 25562306a36Sopenharmony_ci u32 msg_low, pipe_id; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci msg_low = msg->mrfld_header.p.header_low_payload; 25862306a36Sopenharmony_ci msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; 25962306a36Sopenharmony_ci data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); 26062306a36Sopenharmony_ci data_size = msg_low - (sizeof(struct ipc_dsp_hdr)); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci switch (msg_id) { 26362306a36Sopenharmony_ci case IPC_SST_PERIOD_ELAPSED_MRFLD: 26462306a36Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 26562306a36Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 26662306a36Sopenharmony_ci if (str_id > 0) { 26762306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, 26862306a36Sopenharmony_ci "Period elapsed rcvd for pipe id 0x%x\n", 26962306a36Sopenharmony_ci pipe_id); 27062306a36Sopenharmony_ci stream = &sst_drv_ctx->streams[str_id]; 27162306a36Sopenharmony_ci /* If stream is dropped, skip processing this message*/ 27262306a36Sopenharmony_ci if (stream->status == STREAM_INIT) 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci if (stream->period_elapsed) 27562306a36Sopenharmony_ci stream->period_elapsed(stream->pcm_substream); 27662306a36Sopenharmony_ci if (stream->compr_cb) 27762306a36Sopenharmony_ci stream->compr_cb(stream->compr_cb_param); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci case IPC_IA_DRAIN_STREAM_MRFLD: 28262306a36Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 28362306a36Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 28462306a36Sopenharmony_ci if (str_id > 0) { 28562306a36Sopenharmony_ci stream = &sst_drv_ctx->streams[str_id]; 28662306a36Sopenharmony_ci if (stream->drain_notify) 28762306a36Sopenharmony_ci stream->drain_notify(stream->drain_cb_param); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci case IPC_IA_FW_ASYNC_ERR_MRFLD: 29262306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n"); 29362306a36Sopenharmony_ci for (i = 0; i < (data_size/4); i++) 29462306a36Sopenharmony_ci print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, 29562306a36Sopenharmony_ci 16, 4, data_offset, data_size, false); 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci case IPC_IA_FW_INIT_CMPLT_MRFLD: 29962306a36Sopenharmony_ci process_fw_init(sst_drv_ctx, data_offset); 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci case IPC_IA_BUF_UNDER_RUN_MRFLD: 30362306a36Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 30462306a36Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 30562306a36Sopenharmony_ci if (str_id > 0) 30662306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, 30762306a36Sopenharmony_ci "Buffer under-run for pipe:%#x str_id:%d\n", 30862306a36Sopenharmony_ci pipe_id, str_id); 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci default: 31262306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, 31362306a36Sopenharmony_ci "Unrecognized async msg from FW msg_id %#x\n", msg_id); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, 31862306a36Sopenharmony_ci struct ipc_post *msg) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci unsigned int drv_id; 32162306a36Sopenharmony_ci void *data; 32262306a36Sopenharmony_ci union ipc_header_high msg_high; 32362306a36Sopenharmony_ci u32 msg_low; 32462306a36Sopenharmony_ci struct ipc_dsp_hdr *dsp_hdr; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci msg_high = msg->mrfld_header.p.header_high; 32762306a36Sopenharmony_ci msg_low = msg->mrfld_header.p.header_low_payload; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n", 33062306a36Sopenharmony_ci msg->mrfld_header.p.header_high.full, 33162306a36Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci drv_id = msg_high.part.drv_id; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Check for async messages first */ 33662306a36Sopenharmony_ci if (drv_id == SST_ASYNC_DRV_ID) { 33762306a36Sopenharmony_ci /*FW sent async large message*/ 33862306a36Sopenharmony_ci process_fw_async_msg(sst_drv_ctx, msg); 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* FW sent short error response for an IPC */ 34362306a36Sopenharmony_ci if (msg_high.part.result && !msg_high.part.large) { 34462306a36Sopenharmony_ci /* 32-bit FW error code in msg_low */ 34562306a36Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); 34662306a36Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 34762306a36Sopenharmony_ci msg_high.part.drv_id, 34862306a36Sopenharmony_ci msg_high.part.msg_id, NULL, 0); 34962306a36Sopenharmony_ci return; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Process all valid responses 35462306a36Sopenharmony_ci * if it is a large message, the payload contains the size to 35562306a36Sopenharmony_ci * copy from mailbox 35662306a36Sopenharmony_ci **/ 35762306a36Sopenharmony_ci if (msg_high.part.large) { 35862306a36Sopenharmony_ci data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL); 35962306a36Sopenharmony_ci if (!data) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci /* Copy command id so that we can use to put sst to reset */ 36262306a36Sopenharmony_ci dsp_hdr = (struct ipc_dsp_hdr *)data; 36362306a36Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id); 36462306a36Sopenharmony_ci if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 36562306a36Sopenharmony_ci msg_high.part.drv_id, 36662306a36Sopenharmony_ci msg_high.part.msg_id, data, msg_low)) 36762306a36Sopenharmony_ci kfree(data); 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 37062306a36Sopenharmony_ci msg_high.part.drv_id, 37162306a36Sopenharmony_ci msg_high.part.msg_id, NULL, 0); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci} 375