18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sst_ipc.c - Intel SST Driver for audio engine 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008-14 Intel Corporation 68c2ecf20Sopenharmony_ci * Authors: Vinod Koul <vinod.koul@intel.com> 78c2ecf20Sopenharmony_ci * Harsha Priya <priya.harsha@intel.com> 88c2ecf20Sopenharmony_ci * Dharageswari R <dharageswari.r@intel.com> 98c2ecf20Sopenharmony_ci * KP Jeeja <jeeja.kp@intel.com> 108c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/firmware.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/soc.h> 228c2ecf20Sopenharmony_ci#include <sound/compress_driver.h> 238c2ecf20Sopenharmony_ci#include <asm/intel-mid.h> 248c2ecf20Sopenharmony_ci#include <asm/platform_sst_audio.h> 258c2ecf20Sopenharmony_ci#include "../sst-mfld-platform.h" 268c2ecf20Sopenharmony_ci#include "sst.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct sst_block *sst_create_block(struct intel_sst_drv *ctx, 298c2ecf20Sopenharmony_ci u32 msg_id, u32 drv_id) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct sst_block *msg = NULL; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 348c2ecf20Sopenharmony_ci msg = kzalloc(sizeof(*msg), GFP_KERNEL); 358c2ecf20Sopenharmony_ci if (!msg) 368c2ecf20Sopenharmony_ci return NULL; 378c2ecf20Sopenharmony_ci msg->condition = false; 388c2ecf20Sopenharmony_ci msg->on = true; 398c2ecf20Sopenharmony_ci msg->msg_id = msg_id; 408c2ecf20Sopenharmony_ci msg->drv_id = drv_id; 418c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 428c2ecf20Sopenharmony_ci list_add_tail(&msg->node, &ctx->block_list); 438c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return msg; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * while handling the interrupts, we need to check for message status and 508c2ecf20Sopenharmony_ci * then if we are blocking for a message 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * here we are unblocking the blocked ones, this is based on id we have 538c2ecf20Sopenharmony_ci * passed and search that for block threads. 548c2ecf20Sopenharmony_ci * We will not find block in two cases 558c2ecf20Sopenharmony_ci * a) when its small message and block in not there, so silently ignore 568c2ecf20Sopenharmony_ci * them 578c2ecf20Sopenharmony_ci * b) when we are actually not able to find the block (bug perhaps) 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Since we have bit of small messages we can spam kernel log with err 608c2ecf20Sopenharmony_ci * print on above so need to keep as debug prints which should be enabled 618c2ecf20Sopenharmony_ci * via dynamic debug while debugging IPC issues 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ciint sst_wake_up_block(struct intel_sst_drv *ctx, int result, 648c2ecf20Sopenharmony_ci u32 drv_id, u32 ipc, void *data, u32 size) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct sst_block *block = NULL; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 718c2ecf20Sopenharmony_ci list_for_each_entry(block, &ctx->block_list, node) { 728c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id, 738c2ecf20Sopenharmony_ci block->drv_id); 748c2ecf20Sopenharmony_ci if (block->msg_id == ipc && block->drv_id == drv_id) { 758c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "free up the block\n"); 768c2ecf20Sopenharmony_ci block->ret_code = result; 778c2ecf20Sopenharmony_ci block->data = data; 788c2ecf20Sopenharmony_ci block->size = size; 798c2ecf20Sopenharmony_ci block->condition = true; 808c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 818c2ecf20Sopenharmony_ci wake_up(&ctx->wait_queue); 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 868c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, 878c2ecf20Sopenharmony_ci "Block not found or a response received for a short msg for ipc %d, drv_id %d\n", 888c2ecf20Sopenharmony_ci ipc, drv_id); 898c2ecf20Sopenharmony_ci return -EINVAL; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciint sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct sst_block *block = NULL, *__block; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci dev_dbg(ctx->dev, "Enter\n"); 978c2ecf20Sopenharmony_ci spin_lock_bh(&ctx->block_lock); 988c2ecf20Sopenharmony_ci list_for_each_entry_safe(block, __block, &ctx->block_list, node) { 998c2ecf20Sopenharmony_ci if (block == freed) { 1008c2ecf20Sopenharmony_ci pr_debug("pvt_id freed --> %d\n", freed->drv_id); 1018c2ecf20Sopenharmony_ci /* toggle the index position of pvt_id */ 1028c2ecf20Sopenharmony_ci list_del(&freed->node); 1038c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 1048c2ecf20Sopenharmony_ci kfree(freed->data); 1058c2ecf20Sopenharmony_ci freed->data = NULL; 1068c2ecf20Sopenharmony_ci kfree(freed); 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci spin_unlock_bh(&ctx->block_lock); 1118c2ecf20Sopenharmony_ci dev_err(ctx->dev, "block is already freed!!!\n"); 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciint sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, 1168c2ecf20Sopenharmony_ci struct ipc_post *ipc_msg, bool sync) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct ipc_post *msg = ipc_msg; 1198c2ecf20Sopenharmony_ci union ipc_header_mrfld header; 1208c2ecf20Sopenharmony_ci unsigned int loop_count = 0; 1218c2ecf20Sopenharmony_ci int retval = 0; 1228c2ecf20Sopenharmony_ci unsigned long irq_flags; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync); 1258c2ecf20Sopenharmony_ci spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); 1268c2ecf20Sopenharmony_ci header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); 1278c2ecf20Sopenharmony_ci if (sync) { 1288c2ecf20Sopenharmony_ci while (header.p.header_high.part.busy) { 1298c2ecf20Sopenharmony_ci if (loop_count > 25) { 1308c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, 1318c2ecf20Sopenharmony_ci "sst: Busy wait failed, cant send this msg\n"); 1328c2ecf20Sopenharmony_ci retval = -EBUSY; 1338c2ecf20Sopenharmony_ci goto out; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci cpu_relax(); 1368c2ecf20Sopenharmony_ci loop_count++; 1378c2ecf20Sopenharmony_ci header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { 1418c2ecf20Sopenharmony_ci /* queue is empty, nothing to send */ 1428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 1438c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, 1448c2ecf20Sopenharmony_ci "Empty msg queue... NO Action\n"); 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (header.p.header_high.part.busy) { 1498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 1508c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n"); 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* copy msg from list */ 1558c2ecf20Sopenharmony_ci msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, 1568c2ecf20Sopenharmony_ci struct ipc_post, node); 1578c2ecf20Sopenharmony_ci list_del(&msg->node); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n", 1608c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_high.full); 1618c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n", 1628c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (msg->mrfld_header.p.header_high.part.large) 1658c2ecf20Sopenharmony_ci memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, 1668c2ecf20Sopenharmony_ci msg->mailbox_data, 1678c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciout: 1728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 1738c2ecf20Sopenharmony_ci kfree(msg->mailbox_data); 1748c2ecf20Sopenharmony_ci kfree(msg); 1758c2ecf20Sopenharmony_ci return retval; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_civoid intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci union interrupt_reg_mrfld isr; 1818c2ecf20Sopenharmony_ci union interrupt_reg_mrfld imr; 1828c2ecf20Sopenharmony_ci union ipc_header_mrfld clear_ipc; 1838c2ecf20Sopenharmony_ci unsigned long irq_flags; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); 1868c2ecf20Sopenharmony_ci imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); 1878c2ecf20Sopenharmony_ci isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* write 1 to clear*/ 1908c2ecf20Sopenharmony_ci isr.part.busy_interrupt = 1; 1918c2ecf20Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Set IA done bit */ 1948c2ecf20Sopenharmony_ci clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci clear_ipc.p.header_high.part.busy = 0; 1978c2ecf20Sopenharmony_ci clear_ipc.p.header_high.part.done = 1; 1988c2ecf20Sopenharmony_ci clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS; 1998c2ecf20Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full); 2008c2ecf20Sopenharmony_ci /* un mask busy interrupt */ 2018c2ecf20Sopenharmony_ci imr.part.busy_interrupt = 0; 2028c2ecf20Sopenharmony_ci sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); 2038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * process_fw_init - process the FW init msg 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * @msg: IPC message mailbox data from FW 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * This function processes the FW init msg from FW 2138c2ecf20Sopenharmony_ci * marks FW state and prints debug info of loaded FW 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_cistatic void process_fw_init(struct intel_sst_drv *sst_drv_ctx, 2168c2ecf20Sopenharmony_ci void *msg) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct ipc_header_fw_init *init = 2198c2ecf20Sopenharmony_ci (struct ipc_header_fw_init *)msg; 2208c2ecf20Sopenharmony_ci int retval = 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n"); 2238c2ecf20Sopenharmony_ci if (init->result) { 2248c2ecf20Sopenharmony_ci sst_set_fw_state_locked(sst_drv_ctx, SST_RESET); 2258c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n", 2268c2ecf20Sopenharmony_ci init->result); 2278c2ecf20Sopenharmony_ci retval = init->result; 2288c2ecf20Sopenharmony_ci goto ret; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci if (memcmp(&sst_drv_ctx->fw_version, &init->fw_version, 2318c2ecf20Sopenharmony_ci sizeof(init->fw_version))) 2328c2ecf20Sopenharmony_ci dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", 2338c2ecf20Sopenharmony_ci init->fw_version.type, init->fw_version.major, 2348c2ecf20Sopenharmony_ci init->fw_version.minor, init->fw_version.build); 2358c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", 2368c2ecf20Sopenharmony_ci init->build_info.date, init->build_info.time); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Save FW version */ 2398c2ecf20Sopenharmony_ci sst_drv_ctx->fw_version.type = init->fw_version.type; 2408c2ecf20Sopenharmony_ci sst_drv_ctx->fw_version.major = init->fw_version.major; 2418c2ecf20Sopenharmony_ci sst_drv_ctx->fw_version.minor = init->fw_version.minor; 2428c2ecf20Sopenharmony_ci sst_drv_ctx->fw_version.build = init->fw_version.build; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciret: 2458c2ecf20Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, 2498c2ecf20Sopenharmony_ci struct ipc_post *msg) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci u32 msg_id; 2528c2ecf20Sopenharmony_ci int str_id; 2538c2ecf20Sopenharmony_ci u32 data_size, i; 2548c2ecf20Sopenharmony_ci void *data_offset; 2558c2ecf20Sopenharmony_ci struct stream_info *stream; 2568c2ecf20Sopenharmony_ci u32 msg_low, pipe_id; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci msg_low = msg->mrfld_header.p.header_low_payload; 2598c2ecf20Sopenharmony_ci msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; 2608c2ecf20Sopenharmony_ci data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); 2618c2ecf20Sopenharmony_ci data_size = msg_low - (sizeof(struct ipc_dsp_hdr)); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci switch (msg_id) { 2648c2ecf20Sopenharmony_ci case IPC_SST_PERIOD_ELAPSED_MRFLD: 2658c2ecf20Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 2668c2ecf20Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 2678c2ecf20Sopenharmony_ci if (str_id > 0) { 2688c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, 2698c2ecf20Sopenharmony_ci "Period elapsed rcvd for pipe id 0x%x\n", 2708c2ecf20Sopenharmony_ci pipe_id); 2718c2ecf20Sopenharmony_ci stream = &sst_drv_ctx->streams[str_id]; 2728c2ecf20Sopenharmony_ci /* If stream is dropped, skip processing this message*/ 2738c2ecf20Sopenharmony_ci if (stream->status == STREAM_INIT) 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci if (stream->period_elapsed) 2768c2ecf20Sopenharmony_ci stream->period_elapsed(stream->pcm_substream); 2778c2ecf20Sopenharmony_ci if (stream->compr_cb) 2788c2ecf20Sopenharmony_ci stream->compr_cb(stream->compr_cb_param); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci case IPC_IA_DRAIN_STREAM_MRFLD: 2838c2ecf20Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 2848c2ecf20Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 2858c2ecf20Sopenharmony_ci if (str_id > 0) { 2868c2ecf20Sopenharmony_ci stream = &sst_drv_ctx->streams[str_id]; 2878c2ecf20Sopenharmony_ci if (stream->drain_notify) 2888c2ecf20Sopenharmony_ci stream->drain_notify(stream->drain_cb_param); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci case IPC_IA_FW_ASYNC_ERR_MRFLD: 2938c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n"); 2948c2ecf20Sopenharmony_ci for (i = 0; i < (data_size/4); i++) 2958c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, 2968c2ecf20Sopenharmony_ci 16, 4, data_offset, data_size, false); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci case IPC_IA_FW_INIT_CMPLT_MRFLD: 3008c2ecf20Sopenharmony_ci process_fw_init(sst_drv_ctx, data_offset); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci case IPC_IA_BUF_UNDER_RUN_MRFLD: 3048c2ecf20Sopenharmony_ci pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; 3058c2ecf20Sopenharmony_ci str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); 3068c2ecf20Sopenharmony_ci if (str_id > 0) 3078c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, 3088c2ecf20Sopenharmony_ci "Buffer under-run for pipe:%#x str_id:%d\n", 3098c2ecf20Sopenharmony_ci pipe_id, str_id); 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci default: 3138c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, 3148c2ecf20Sopenharmony_ci "Unrecognized async msg from FW msg_id %#x\n", msg_id); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_civoid sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, 3198c2ecf20Sopenharmony_ci struct ipc_post *msg) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci unsigned int drv_id; 3228c2ecf20Sopenharmony_ci void *data; 3238c2ecf20Sopenharmony_ci union ipc_header_high msg_high; 3248c2ecf20Sopenharmony_ci u32 msg_low; 3258c2ecf20Sopenharmony_ci struct ipc_dsp_hdr *dsp_hdr; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci msg_high = msg->mrfld_header.p.header_high; 3288c2ecf20Sopenharmony_ci msg_low = msg->mrfld_header.p.header_low_payload; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n", 3318c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_high.full, 3328c2ecf20Sopenharmony_ci msg->mrfld_header.p.header_low_payload); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci drv_id = msg_high.part.drv_id; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Check for async messages first */ 3378c2ecf20Sopenharmony_ci if (drv_id == SST_ASYNC_DRV_ID) { 3388c2ecf20Sopenharmony_ci /*FW sent async large message*/ 3398c2ecf20Sopenharmony_ci process_fw_async_msg(sst_drv_ctx, msg); 3408c2ecf20Sopenharmony_ci return; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* FW sent short error response for an IPC */ 3448c2ecf20Sopenharmony_ci if (msg_high.part.result && drv_id && !msg_high.part.large) { 3458c2ecf20Sopenharmony_ci /* 32-bit FW error code in msg_low */ 3468c2ecf20Sopenharmony_ci dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); 3478c2ecf20Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 3488c2ecf20Sopenharmony_ci msg_high.part.drv_id, 3498c2ecf20Sopenharmony_ci msg_high.part.msg_id, NULL, 0); 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Process all valid responses 3558c2ecf20Sopenharmony_ci * if it is a large message, the payload contains the size to 3568c2ecf20Sopenharmony_ci * copy from mailbox 3578c2ecf20Sopenharmony_ci **/ 3588c2ecf20Sopenharmony_ci if (msg_high.part.large) { 3598c2ecf20Sopenharmony_ci data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL); 3608c2ecf20Sopenharmony_ci if (!data) 3618c2ecf20Sopenharmony_ci return; 3628c2ecf20Sopenharmony_ci /* Copy command id so that we can use to put sst to reset */ 3638c2ecf20Sopenharmony_ci dsp_hdr = (struct ipc_dsp_hdr *)data; 3648c2ecf20Sopenharmony_ci dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id); 3658c2ecf20Sopenharmony_ci if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 3668c2ecf20Sopenharmony_ci msg_high.part.drv_id, 3678c2ecf20Sopenharmony_ci msg_high.part.msg_id, data, msg_low)) 3688c2ecf20Sopenharmony_ci kfree(data); 3698c2ecf20Sopenharmony_ci } else { 3708c2ecf20Sopenharmony_ci sst_wake_up_block(sst_drv_ctx, msg_high.part.result, 3718c2ecf20Sopenharmony_ci msg_high.part.drv_id, 3728c2ecf20Sopenharmony_ci msg_high.part.msg_id, NULL, 0); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci} 376