Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license.  When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2021 Intel Corporation. All rights reserved.
0007 //
0008 //
0009 
0010 #include <sound/sof/stream.h>
0011 #include <sound/sof/control.h>
0012 #include "sof-priv.h"
0013 #include "sof-audio.h"
0014 #include "ipc3-priv.h"
0015 #include "ops.h"
0016 
0017 typedef void (*ipc3_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);
0018 
0019 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
0020 static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
0021 {
0022     u8 *str;
0023     u8 *str2 = NULL;
0024     u32 glb;
0025     u32 type;
0026     bool vdbg = false;
0027 
0028     glb = cmd & SOF_GLB_TYPE_MASK;
0029     type = cmd & SOF_CMD_TYPE_MASK;
0030 
0031     switch (glb) {
0032     case SOF_IPC_GLB_REPLY:
0033         str = "GLB_REPLY"; break;
0034     case SOF_IPC_GLB_COMPOUND:
0035         str = "GLB_COMPOUND"; break;
0036     case SOF_IPC_GLB_TPLG_MSG:
0037         str = "GLB_TPLG_MSG";
0038         switch (type) {
0039         case SOF_IPC_TPLG_COMP_NEW:
0040             str2 = "COMP_NEW"; break;
0041         case SOF_IPC_TPLG_COMP_FREE:
0042             str2 = "COMP_FREE"; break;
0043         case SOF_IPC_TPLG_COMP_CONNECT:
0044             str2 = "COMP_CONNECT"; break;
0045         case SOF_IPC_TPLG_PIPE_NEW:
0046             str2 = "PIPE_NEW"; break;
0047         case SOF_IPC_TPLG_PIPE_FREE:
0048             str2 = "PIPE_FREE"; break;
0049         case SOF_IPC_TPLG_PIPE_CONNECT:
0050             str2 = "PIPE_CONNECT"; break;
0051         case SOF_IPC_TPLG_PIPE_COMPLETE:
0052             str2 = "PIPE_COMPLETE"; break;
0053         case SOF_IPC_TPLG_BUFFER_NEW:
0054             str2 = "BUFFER_NEW"; break;
0055         case SOF_IPC_TPLG_BUFFER_FREE:
0056             str2 = "BUFFER_FREE"; break;
0057         default:
0058             str2 = "unknown type"; break;
0059         }
0060         break;
0061     case SOF_IPC_GLB_PM_MSG:
0062         str = "GLB_PM_MSG";
0063         switch (type) {
0064         case SOF_IPC_PM_CTX_SAVE:
0065             str2 = "CTX_SAVE"; break;
0066         case SOF_IPC_PM_CTX_RESTORE:
0067             str2 = "CTX_RESTORE"; break;
0068         case SOF_IPC_PM_CTX_SIZE:
0069             str2 = "CTX_SIZE"; break;
0070         case SOF_IPC_PM_CLK_SET:
0071             str2 = "CLK_SET"; break;
0072         case SOF_IPC_PM_CLK_GET:
0073             str2 = "CLK_GET"; break;
0074         case SOF_IPC_PM_CLK_REQ:
0075             str2 = "CLK_REQ"; break;
0076         case SOF_IPC_PM_CORE_ENABLE:
0077             str2 = "CORE_ENABLE"; break;
0078         case SOF_IPC_PM_GATE:
0079             str2 = "GATE"; break;
0080         default:
0081             str2 = "unknown type"; break;
0082         }
0083         break;
0084     case SOF_IPC_GLB_COMP_MSG:
0085         str = "GLB_COMP_MSG";
0086         switch (type) {
0087         case SOF_IPC_COMP_SET_VALUE:
0088             str2 = "SET_VALUE"; break;
0089         case SOF_IPC_COMP_GET_VALUE:
0090             str2 = "GET_VALUE"; break;
0091         case SOF_IPC_COMP_SET_DATA:
0092             str2 = "SET_DATA"; break;
0093         case SOF_IPC_COMP_GET_DATA:
0094             str2 = "GET_DATA"; break;
0095         default:
0096             str2 = "unknown type"; break;
0097         }
0098         break;
0099     case SOF_IPC_GLB_STREAM_MSG:
0100         str = "GLB_STREAM_MSG";
0101         switch (type) {
0102         case SOF_IPC_STREAM_PCM_PARAMS:
0103             str2 = "PCM_PARAMS"; break;
0104         case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
0105             str2 = "PCM_REPLY"; break;
0106         case SOF_IPC_STREAM_PCM_FREE:
0107             str2 = "PCM_FREE"; break;
0108         case SOF_IPC_STREAM_TRIG_START:
0109             str2 = "TRIG_START"; break;
0110         case SOF_IPC_STREAM_TRIG_STOP:
0111             str2 = "TRIG_STOP"; break;
0112         case SOF_IPC_STREAM_TRIG_PAUSE:
0113             str2 = "TRIG_PAUSE"; break;
0114         case SOF_IPC_STREAM_TRIG_RELEASE:
0115             str2 = "TRIG_RELEASE"; break;
0116         case SOF_IPC_STREAM_TRIG_DRAIN:
0117             str2 = "TRIG_DRAIN"; break;
0118         case SOF_IPC_STREAM_TRIG_XRUN:
0119             str2 = "TRIG_XRUN"; break;
0120         case SOF_IPC_STREAM_POSITION:
0121             vdbg = true;
0122             str2 = "POSITION"; break;
0123         case SOF_IPC_STREAM_VORBIS_PARAMS:
0124             str2 = "VORBIS_PARAMS"; break;
0125         case SOF_IPC_STREAM_VORBIS_FREE:
0126             str2 = "VORBIS_FREE"; break;
0127         default:
0128             str2 = "unknown type"; break;
0129         }
0130         break;
0131     case SOF_IPC_FW_READY:
0132         str = "FW_READY"; break;
0133     case SOF_IPC_GLB_DAI_MSG:
0134         str = "GLB_DAI_MSG";
0135         switch (type) {
0136         case SOF_IPC_DAI_CONFIG:
0137             str2 = "CONFIG"; break;
0138         case SOF_IPC_DAI_LOOPBACK:
0139             str2 = "LOOPBACK"; break;
0140         default:
0141             str2 = "unknown type"; break;
0142         }
0143         break;
0144     case SOF_IPC_GLB_TRACE_MSG:
0145         str = "GLB_TRACE_MSG";
0146         switch (type) {
0147         case SOF_IPC_TRACE_DMA_PARAMS:
0148             str2 = "DMA_PARAMS"; break;
0149         case SOF_IPC_TRACE_DMA_POSITION:
0150             if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS))
0151                 return;
0152             str2 = "DMA_POSITION"; break;
0153         case SOF_IPC_TRACE_DMA_PARAMS_EXT:
0154             str2 = "DMA_PARAMS_EXT"; break;
0155         case SOF_IPC_TRACE_FILTER_UPDATE:
0156             str2 = "FILTER_UPDATE"; break;
0157         case SOF_IPC_TRACE_DMA_FREE:
0158             str2 = "DMA_FREE"; break;
0159         default:
0160             str2 = "unknown type"; break;
0161         }
0162         break;
0163     case SOF_IPC_GLB_TEST_MSG:
0164         str = "GLB_TEST_MSG";
0165         switch (type) {
0166         case SOF_IPC_TEST_IPC_FLOOD:
0167             str2 = "IPC_FLOOD"; break;
0168         default:
0169             str2 = "unknown type"; break;
0170         }
0171         break;
0172     case SOF_IPC_GLB_DEBUG:
0173         str = "GLB_DEBUG";
0174         switch (type) {
0175         case SOF_IPC_DEBUG_MEM_USAGE:
0176             str2 = "MEM_USAGE"; break;
0177         default:
0178             str2 = "unknown type"; break;
0179         }
0180         break;
0181     case SOF_IPC_GLB_PROBE:
0182         str = "GLB_PROBE";
0183         switch (type) {
0184         case SOF_IPC_PROBE_INIT:
0185             str2 = "INIT"; break;
0186         case SOF_IPC_PROBE_DEINIT:
0187             str2 = "DEINIT"; break;
0188         case SOF_IPC_PROBE_DMA_ADD:
0189             str2 = "DMA_ADD"; break;
0190         case SOF_IPC_PROBE_DMA_INFO:
0191             str2 = "DMA_INFO"; break;
0192         case SOF_IPC_PROBE_DMA_REMOVE:
0193             str2 = "DMA_REMOVE"; break;
0194         case SOF_IPC_PROBE_POINT_ADD:
0195             str2 = "POINT_ADD"; break;
0196         case SOF_IPC_PROBE_POINT_INFO:
0197             str2 = "POINT_INFO"; break;
0198         case SOF_IPC_PROBE_POINT_REMOVE:
0199             str2 = "POINT_REMOVE"; break;
0200         default:
0201             str2 = "unknown type"; break;
0202         }
0203         break;
0204     default:
0205         str = "unknown GLB command"; break;
0206     }
0207 
0208     if (str2) {
0209         if (vdbg)
0210             dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
0211         else
0212             dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
0213     } else {
0214         dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
0215     }
0216 }
0217 #else
0218 static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
0219 {
0220     if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG)
0221         dev_dbg(dev, "%s: 0x%x\n", text, cmd);
0222 }
0223 #endif
0224 
0225 static int sof_ipc3_get_reply(struct snd_sof_dev *sdev)
0226 {
0227     struct snd_sof_ipc_msg *msg = sdev->msg;
0228     struct sof_ipc_reply *reply;
0229     int ret = 0;
0230 
0231     /* get the generic reply */
0232     reply = msg->reply_data;
0233     snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply));
0234 
0235     if (reply->error < 0)
0236         return reply->error;
0237 
0238     if (!reply->hdr.size) {
0239         /* Reply should always be >= sizeof(struct sof_ipc_reply) */
0240         if (msg->reply_size)
0241             dev_err(sdev->dev,
0242                 "empty reply received, expected %zu bytes\n",
0243                 msg->reply_size);
0244         else
0245             dev_err(sdev->dev, "empty reply received\n");
0246 
0247         return -EINVAL;
0248     }
0249 
0250     if (msg->reply_size > 0) {
0251         if (reply->hdr.size == msg->reply_size) {
0252             ret = 0;
0253         } else if (reply->hdr.size < msg->reply_size) {
0254             dev_dbg(sdev->dev,
0255                 "reply size (%u) is less than expected (%zu)\n",
0256                 reply->hdr.size, msg->reply_size);
0257 
0258             msg->reply_size = reply->hdr.size;
0259             ret = 0;
0260         } else {
0261             dev_err(sdev->dev,
0262                 "reply size (%u) exceeds the buffer size (%zu)\n",
0263                 reply->hdr.size, msg->reply_size);
0264             ret = -EINVAL;
0265         }
0266 
0267         /*
0268          * get the full message if reply->hdr.size <= msg->reply_size
0269          * and the reply->hdr.size > sizeof(struct sof_ipc_reply)
0270          */
0271         if (!ret && msg->reply_size > sizeof(*reply))
0272             snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset,
0273                          msg->reply_data, msg->reply_size);
0274     }
0275 
0276     return ret;
0277 }
0278 
0279 /* wait for IPC message reply */
0280 static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
0281 {
0282     struct snd_sof_ipc_msg *msg = &ipc->msg;
0283     struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
0284     struct snd_sof_dev *sdev = ipc->sdev;
0285     int ret;
0286 
0287     /* wait for DSP IPC completion */
0288     ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
0289                  msecs_to_jiffies(sdev->ipc_timeout));
0290 
0291     if (ret == 0) {
0292         dev_err(sdev->dev,
0293             "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n",
0294             hdr->cmd, hdr->size, msg->reply_size);
0295         snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout");
0296         ret = -ETIMEDOUT;
0297     } else {
0298         ret = msg->reply_error;
0299         if (ret < 0) {
0300             dev_err(sdev->dev,
0301                 "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n",
0302                 hdr->cmd, hdr->size, msg->reply_size, ret);
0303         } else {
0304             if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
0305                 ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
0306             if (msg->reply_size)
0307                 /* copy the data returned from DSP */
0308                 memcpy(reply_data, msg->reply_data,
0309                        msg->reply_size);
0310         }
0311 
0312         /* re-enable dumps after successful IPC tx */
0313         if (sdev->ipc_dump_printed) {
0314             sdev->dbg_dump_printed = false;
0315             sdev->ipc_dump_printed = false;
0316         }
0317     }
0318 
0319     return ret;
0320 }
0321 
0322 /* send IPC message from host to DSP */
0323 static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
0324                 void *msg_data, size_t msg_bytes,
0325                 void *reply_data, size_t reply_bytes)
0326 {
0327     struct sof_ipc_cmd_hdr *hdr = msg_data;
0328     struct snd_sof_dev *sdev = ipc->sdev;
0329     int ret;
0330 
0331     ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
0332 
0333     if (ret) {
0334         dev_err_ratelimited(sdev->dev,
0335                     "%s: ipc message send for %#x failed: %d\n",
0336                     __func__, hdr->cmd, ret);
0337         return ret;
0338     }
0339 
0340     ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
0341 
0342     /* now wait for completion */
0343     return ipc3_wait_tx_done(ipc, reply_data);
0344 }
0345 
0346 static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
0347                void *reply_data, size_t reply_bytes, bool no_pm)
0348 {
0349     struct snd_sof_ipc *ipc = sdev->ipc;
0350     int ret;
0351 
0352     if (!msg_data || msg_bytes < sizeof(struct sof_ipc_cmd_hdr)) {
0353         dev_err_ratelimited(sdev->dev, "No IPC message to send\n");
0354         return -EINVAL;
0355     }
0356 
0357     if (!no_pm) {
0358         const struct sof_dsp_power_state target_state = {
0359             .state = SOF_DSP_PM_D0,
0360         };
0361 
0362         /* ensure the DSP is in D0 before sending a new IPC */
0363         ret = snd_sof_dsp_set_power_state(sdev, &target_state);
0364         if (ret < 0) {
0365             dev_err(sdev->dev, "%s: resuming DSP failed: %d\n",
0366                 __func__, ret);
0367             return ret;
0368         }
0369     }
0370 
0371     /* Serialise IPC TX */
0372     mutex_lock(&ipc->tx_mutex);
0373 
0374     ret = ipc3_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes);
0375 
0376     mutex_unlock(&ipc->tx_mutex);
0377 
0378     return ret;
0379 }
0380 
0381 static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
0382                  bool set)
0383 {
0384     size_t msg_bytes, hdr_bytes, payload_size, send_bytes;
0385     struct sof_ipc_ctrl_data *cdata = data;
0386     struct sof_ipc_ctrl_data *cdata_chunk;
0387     struct snd_sof_ipc *ipc = sdev->ipc;
0388     size_t offset = 0;
0389     u8 *src, *dst;
0390     u32 num_msg;
0391     int ret = 0;
0392     int i;
0393 
0394     if (!cdata || data_bytes < sizeof(*cdata))
0395         return -EINVAL;
0396 
0397     if ((cdata->rhdr.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_COMP_MSG) {
0398         dev_err(sdev->dev, "%s: Not supported message type of %#x\n",
0399             __func__, cdata->rhdr.hdr.cmd);
0400         return -EINVAL;
0401     }
0402 
0403     /* send normal size ipc in one part */
0404     if (cdata->rhdr.hdr.size <= ipc->max_payload_size)
0405         return sof_ipc3_tx_msg(sdev, cdata, cdata->rhdr.hdr.size,
0406                        cdata, cdata->rhdr.hdr.size, false);
0407 
0408     cdata_chunk = kzalloc(ipc->max_payload_size, GFP_KERNEL);
0409     if (!cdata_chunk)
0410         return -ENOMEM;
0411 
0412     switch (cdata->type) {
0413     case SOF_CTRL_TYPE_VALUE_CHAN_GET:
0414     case SOF_CTRL_TYPE_VALUE_CHAN_SET:
0415         hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
0416         if (set) {
0417             src = (u8 *)cdata->chanv;
0418             dst = (u8 *)cdata_chunk->chanv;
0419         } else {
0420             src = (u8 *)cdata_chunk->chanv;
0421             dst = (u8 *)cdata->chanv;
0422         }
0423         break;
0424     case SOF_CTRL_TYPE_DATA_GET:
0425     case SOF_CTRL_TYPE_DATA_SET:
0426         hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr);
0427         if (set) {
0428             src = (u8 *)cdata->data->data;
0429             dst = (u8 *)cdata_chunk->data->data;
0430         } else {
0431             src = (u8 *)cdata_chunk->data->data;
0432             dst = (u8 *)cdata->data->data;
0433         }
0434         break;
0435     default:
0436         kfree(cdata_chunk);
0437         return -EINVAL;
0438     }
0439 
0440     msg_bytes = cdata->rhdr.hdr.size - hdr_bytes;
0441     payload_size = ipc->max_payload_size - hdr_bytes;
0442     num_msg = DIV_ROUND_UP(msg_bytes, payload_size);
0443 
0444     /* copy the header data */
0445     memcpy(cdata_chunk, cdata, hdr_bytes);
0446 
0447     /* Serialise IPC TX */
0448     mutex_lock(&sdev->ipc->tx_mutex);
0449 
0450     /* copy the payload data in a loop */
0451     for (i = 0; i < num_msg; i++) {
0452         send_bytes = min(msg_bytes, payload_size);
0453         cdata_chunk->num_elems = send_bytes;
0454         cdata_chunk->rhdr.hdr.size = hdr_bytes + send_bytes;
0455         cdata_chunk->msg_index = i;
0456         msg_bytes -= send_bytes;
0457         cdata_chunk->elems_remaining = msg_bytes;
0458 
0459         if (set)
0460             memcpy(dst, src + offset, send_bytes);
0461 
0462         ret = ipc3_tx_msg_unlocked(sdev->ipc,
0463                        cdata_chunk, cdata_chunk->rhdr.hdr.size,
0464                        cdata_chunk, cdata_chunk->rhdr.hdr.size);
0465         if (ret < 0)
0466             break;
0467 
0468         if (!set)
0469             memcpy(dst + offset, src, send_bytes);
0470 
0471         offset += payload_size;
0472     }
0473 
0474     mutex_unlock(&sdev->ipc->tx_mutex);
0475 
0476     kfree(cdata_chunk);
0477 
0478     return ret;
0479 }
0480 
0481 int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
0482                  const struct sof_ipc_ext_data_hdr *ext_hdr)
0483 {
0484     const struct sof_ipc_window *w =
0485         container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
0486 
0487     if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
0488         return -EINVAL;
0489 
0490     if (sdev->info_window) {
0491         if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
0492             dev_err(sdev->dev, "mismatch between window descriptor from extended manifest and mailbox");
0493             return -EINVAL;
0494         }
0495         return 0;
0496     }
0497 
0498     /* keep a local copy of the data */
0499     sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, GFP_KERNEL);
0500     if (!sdev->info_window)
0501         return -ENOMEM;
0502 
0503     return 0;
0504 }
0505 
0506 int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
0507              const struct sof_ipc_ext_data_hdr *ext_hdr)
0508 {
0509     int ret;
0510 
0511     const struct sof_ipc_cc_version *cc =
0512         container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
0513 
0514     if (sdev->cc_version) {
0515         if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
0516             dev_err(sdev->dev,
0517                 "Receive diverged cc_version descriptions");
0518             return -EINVAL;
0519         }
0520         return 0;
0521     }
0522 
0523     dev_dbg(sdev->dev,
0524         "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
0525         cc->name, cc->major, cc->minor, cc->micro, cc->desc, cc->optim);
0526 
0527     /* create read-only cc_version debugfs to store compiler version info */
0528     /* use local copy of the cc_version to prevent data corruption */
0529     if (sdev->first_boot) {
0530         sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
0531                         GFP_KERNEL);
0532 
0533         if (!sdev->cc_version)
0534             return -ENOMEM;
0535 
0536         memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
0537         ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
0538                            cc->ext_hdr.hdr.size,
0539                            "cc_version", 0444);
0540 
0541         /* errors are only due to memory allocation, not debugfs */
0542         if (ret < 0) {
0543             dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n");
0544             return ret;
0545         }
0546     }
0547 
0548     return 0;
0549 }
0550 
0551 /* parse the extended FW boot data structures from FW boot message */
0552 static int ipc3_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
0553 {
0554     struct sof_ipc_ext_data_hdr *ext_hdr;
0555     void *ext_data;
0556     int ret = 0;
0557 
0558     ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
0559     if (!ext_data)
0560         return -ENOMEM;
0561 
0562     /* get first header */
0563     snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
0564                    sizeof(*ext_hdr));
0565     ext_hdr = ext_data;
0566 
0567     while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
0568         /* read in ext structure */
0569         snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
0570                        offset + sizeof(*ext_hdr),
0571                        (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
0572                        ext_hdr->hdr.size - sizeof(*ext_hdr));
0573 
0574         dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
0575             ext_hdr->type, ext_hdr->hdr.size);
0576 
0577         /* process structure data */
0578         switch (ext_hdr->type) {
0579         case SOF_IPC_EXT_WINDOW:
0580             ret = sof_ipc3_get_ext_windows(sdev, ext_hdr);
0581             break;
0582         case SOF_IPC_EXT_CC_INFO:
0583             ret = sof_ipc3_get_cc_info(sdev, ext_hdr);
0584             break;
0585         case SOF_IPC_EXT_UNUSED:
0586         case SOF_IPC_EXT_PROBE_INFO:
0587         case SOF_IPC_EXT_USER_ABI_INFO:
0588             /* They are supported but we don't do anything here */
0589             break;
0590         default:
0591             dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
0592                  ext_hdr->type, ext_hdr->hdr.size);
0593             ret = 0;
0594             break;
0595         }
0596 
0597         if (ret < 0) {
0598             dev_err(sdev->dev, "Failed to parse ext data type %d\n",
0599                 ext_hdr->type);
0600             break;
0601         }
0602 
0603         /* move to next header */
0604         offset += ext_hdr->hdr.size;
0605         snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
0606                        sizeof(*ext_hdr));
0607         ext_hdr = ext_data;
0608     }
0609 
0610     kfree(ext_data);
0611     return ret;
0612 }
0613 
0614 static void ipc3_get_windows(struct snd_sof_dev *sdev)
0615 {
0616     struct sof_ipc_window_elem *elem;
0617     u32 outbox_offset = 0;
0618     u32 stream_offset = 0;
0619     u32 inbox_offset = 0;
0620     u32 outbox_size = 0;
0621     u32 stream_size = 0;
0622     u32 inbox_size = 0;
0623     u32 debug_size = 0;
0624     u32 debug_offset = 0;
0625     int window_offset;
0626     int i;
0627 
0628     if (!sdev->info_window) {
0629         dev_err(sdev->dev, "%s: No window info present\n", __func__);
0630         return;
0631     }
0632 
0633     for (i = 0; i < sdev->info_window->num_windows; i++) {
0634         elem = &sdev->info_window->window[i];
0635 
0636         window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
0637         if (window_offset < 0) {
0638             dev_warn(sdev->dev, "No offset for window %d\n", elem->id);
0639             continue;
0640         }
0641 
0642         switch (elem->type) {
0643         case SOF_IPC_REGION_UPBOX:
0644             inbox_offset = window_offset + elem->offset;
0645             inbox_size = elem->size;
0646             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0647                             inbox_offset,
0648                             elem->size, "inbox",
0649                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0650             break;
0651         case SOF_IPC_REGION_DOWNBOX:
0652             outbox_offset = window_offset + elem->offset;
0653             outbox_size = elem->size;
0654             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0655                             outbox_offset,
0656                             elem->size, "outbox",
0657                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0658             break;
0659         case SOF_IPC_REGION_TRACE:
0660             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0661                             window_offset + elem->offset,
0662                             elem->size, "etrace",
0663                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0664             break;
0665         case SOF_IPC_REGION_DEBUG:
0666             debug_offset = window_offset + elem->offset;
0667             debug_size = elem->size;
0668             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0669                             window_offset + elem->offset,
0670                             elem->size, "debug",
0671                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0672             break;
0673         case SOF_IPC_REGION_STREAM:
0674             stream_offset = window_offset + elem->offset;
0675             stream_size = elem->size;
0676             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0677                             stream_offset,
0678                             elem->size, "stream",
0679                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0680             break;
0681         case SOF_IPC_REGION_REGS:
0682             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0683                             window_offset + elem->offset,
0684                             elem->size, "regs",
0685                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0686             break;
0687         case SOF_IPC_REGION_EXCEPTION:
0688             sdev->dsp_oops_offset = window_offset + elem->offset;
0689             snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
0690                             window_offset + elem->offset,
0691                             elem->size, "exception",
0692                             SOF_DEBUGFS_ACCESS_D0_ONLY);
0693             break;
0694         default:
0695             dev_err(sdev->dev, "%s: Illegal window info: %u\n",
0696                 __func__, elem->type);
0697             return;
0698         }
0699     }
0700 
0701     if (outbox_size == 0 || inbox_size == 0) {
0702         dev_err(sdev->dev, "%s: Illegal mailbox window\n", __func__);
0703         return;
0704     }
0705 
0706     sdev->dsp_box.offset = inbox_offset;
0707     sdev->dsp_box.size = inbox_size;
0708 
0709     sdev->host_box.offset = outbox_offset;
0710     sdev->host_box.size = outbox_size;
0711 
0712     sdev->stream_box.offset = stream_offset;
0713     sdev->stream_box.size = stream_size;
0714 
0715     sdev->debug_box.offset = debug_offset;
0716     sdev->debug_box.size = debug_size;
0717 
0718     dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
0719         inbox_offset, inbox_size);
0720     dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
0721         outbox_offset, outbox_size);
0722     dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
0723         stream_offset, stream_size);
0724     dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
0725         debug_offset, debug_size);
0726 }
0727 
0728 static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
0729 {
0730     struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
0731 
0732     msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
0733     if (!msg->reply_data)
0734         return -ENOMEM;
0735 
0736     sdev->ipc->max_payload_size = SOF_IPC_MSG_MAX_SIZE;
0737 
0738     return 0;
0739 }
0740 
0741 int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
0742 {
0743     struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
0744     struct sof_ipc_fw_version *v = &ready->version;
0745 
0746     dev_info(sdev->dev,
0747          "Firmware info: version %d:%d:%d-%s\n",  v->major, v->minor,
0748          v->micro, v->tag);
0749     dev_info(sdev->dev,
0750          "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
0751          SOF_ABI_VERSION_MAJOR(v->abi_version),
0752          SOF_ABI_VERSION_MINOR(v->abi_version),
0753          SOF_ABI_VERSION_PATCH(v->abi_version),
0754          SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
0755 
0756     if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
0757         dev_err(sdev->dev, "incompatible FW ABI version\n");
0758         return -EINVAL;
0759     }
0760 
0761     if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
0762         SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
0763         dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
0764         return -EINVAL;
0765     }
0766 
0767     if (ready->flags & SOF_IPC_INFO_BUILD) {
0768         dev_info(sdev->dev,
0769              "Firmware debug build %d on %s-%s - options:\n"
0770              " GDB: %s\n"
0771              " lock debug: %s\n"
0772              " lock vdebug: %s\n",
0773              v->build, v->date, v->time,
0774              (ready->flags & SOF_IPC_INFO_GDB) ?
0775                 "enabled" : "disabled",
0776              (ready->flags & SOF_IPC_INFO_LOCKS) ?
0777                 "enabled" : "disabled",
0778              (ready->flags & SOF_IPC_INFO_LOCKSV) ?
0779                 "enabled" : "disabled");
0780     }
0781 
0782     /* copy the fw_version into debugfs at first boot */
0783     memcpy(&sdev->fw_version, v, sizeof(*v));
0784 
0785     return 0;
0786 }
0787 
0788 static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
0789 {
0790     struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
0791     int offset;
0792     int ret;
0793 
0794     /* mailbox must be on 4k boundary */
0795     offset = snd_sof_dsp_get_mailbox_offset(sdev);
0796     if (offset < 0) {
0797         dev_err(sdev->dev, "%s: no mailbox offset\n", __func__);
0798         return offset;
0799     }
0800 
0801     dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
0802 
0803     /* no need to re-check version/ABI for subsequent boots */
0804     if (!sdev->first_boot)
0805         return 0;
0806 
0807     /*
0808      * copy data from the DSP FW ready offset
0809      * Subsequent error handling is not needed for BLK_TYPE_SRAM
0810      */
0811     ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
0812                      sizeof(*fw_ready));
0813     if (ret) {
0814         dev_err(sdev->dev,
0815             "Unable to read fw_ready, read from TYPE_SRAM failed\n");
0816         return ret;
0817     }
0818 
0819     /* make sure ABI version is compatible */
0820     ret = sof_ipc3_validate_fw_version(sdev);
0821     if (ret < 0)
0822         return ret;
0823 
0824     /* now check for extended data */
0825     ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
0826 
0827     ipc3_get_windows(sdev);
0828 
0829     return ipc3_init_reply_data_buffer(sdev);
0830 }
0831 
0832 /* IPC stream position. */
0833 static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
0834 {
0835     struct snd_soc_component *scomp = sdev->component;
0836     struct snd_sof_pcm_stream *stream;
0837     struct sof_ipc_stream_posn posn;
0838     struct snd_sof_pcm *spcm;
0839     int direction, ret;
0840 
0841     spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
0842     if (!spcm) {
0843         dev_err(sdev->dev, "period elapsed for unknown stream, msg_id %d\n",
0844             msg_id);
0845         return;
0846     }
0847 
0848     stream = &spcm->stream[direction];
0849     ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
0850     if (ret < 0) {
0851         dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
0852         return;
0853     }
0854 
0855     dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n",
0856          posn.host_posn, posn.dai_posn, posn.wallclock);
0857 
0858     memcpy(&stream->posn, &posn, sizeof(posn));
0859 
0860     if (spcm->pcm.compress)
0861         snd_sof_compr_fragment_elapsed(stream->cstream);
0862     else if (stream->substream->runtime &&
0863          !stream->substream->runtime->no_period_wakeup)
0864         /* only inform ALSA for period_wakeup mode */
0865         snd_sof_pcm_period_elapsed(stream->substream);
0866 }
0867 
0868 /* DSP notifies host of an XRUN within FW */
0869 static void ipc3_xrun(struct snd_sof_dev *sdev, u32 msg_id)
0870 {
0871     struct snd_soc_component *scomp = sdev->component;
0872     struct snd_sof_pcm_stream *stream;
0873     struct sof_ipc_stream_posn posn;
0874     struct snd_sof_pcm *spcm;
0875     int direction, ret;
0876 
0877     spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
0878     if (!spcm) {
0879         dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n",
0880             msg_id);
0881         return;
0882     }
0883 
0884     stream = &spcm->stream[direction];
0885     ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
0886     if (ret < 0) {
0887         dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret);
0888         return;
0889     }
0890 
0891     dev_dbg(sdev->dev,  "posn XRUN: host %llx comp %d size %d\n",
0892         posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
0893 
0894 #if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP)
0895     /* stop PCM on XRUN - used for pipeline debug */
0896     memcpy(&stream->posn, &posn, sizeof(posn));
0897     snd_pcm_stop_xrun(stream->substream);
0898 #endif
0899 }
0900 
0901 /* stream notifications from firmware */
0902 static void ipc3_stream_message(struct snd_sof_dev *sdev, void *msg_buf)
0903 {
0904     struct sof_ipc_cmd_hdr *hdr = msg_buf;
0905     u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
0906     u32 msg_id = SOF_IPC_MESSAGE_ID(hdr->cmd);
0907 
0908     switch (msg_type) {
0909     case SOF_IPC_STREAM_POSITION:
0910         ipc3_period_elapsed(sdev, msg_id);
0911         break;
0912     case SOF_IPC_STREAM_TRIG_XRUN:
0913         ipc3_xrun(sdev, msg_id);
0914         break;
0915     default:
0916         dev_err(sdev->dev, "unhandled stream message %#x\n",
0917             msg_id);
0918         break;
0919     }
0920 }
0921 
0922 /* component notifications from firmware */
0923 static void ipc3_comp_notification(struct snd_sof_dev *sdev, void *msg_buf)
0924 {
0925     const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
0926     struct sof_ipc_cmd_hdr *hdr = msg_buf;
0927     u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
0928 
0929     switch (msg_type) {
0930     case SOF_IPC_COMP_GET_VALUE:
0931     case SOF_IPC_COMP_GET_DATA:
0932         break;
0933     default:
0934         dev_err(sdev->dev, "unhandled component message %#x\n", msg_type);
0935         return;
0936     }
0937 
0938     if (tplg_ops->control->update)
0939         tplg_ops->control->update(sdev, msg_buf);
0940 }
0941 
0942 static void ipc3_trace_message(struct snd_sof_dev *sdev, void *msg_buf)
0943 {
0944     struct sof_ipc_cmd_hdr *hdr = msg_buf;
0945     u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
0946 
0947     switch (msg_type) {
0948     case SOF_IPC_TRACE_DMA_POSITION:
0949         ipc3_dtrace_posn_update(sdev, msg_buf);
0950         break;
0951     default:
0952         dev_err(sdev->dev, "unhandled trace message %#x\n", msg_type);
0953         break;
0954     }
0955 }
0956 
0957 /* DSP firmware has sent host a message  */
0958 static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
0959 {
0960     ipc3_rx_callback rx_callback = NULL;
0961     struct sof_ipc_cmd_hdr hdr;
0962     void *msg_buf;
0963     u32 cmd;
0964     int err;
0965 
0966     /* read back header */
0967     err = snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr));
0968     if (err < 0) {
0969         dev_warn(sdev->dev, "failed to read IPC header: %d\n", err);
0970         return;
0971     }
0972 
0973     if (hdr.size < sizeof(hdr)) {
0974         dev_err(sdev->dev, "The received message size is invalid\n");
0975         return;
0976     }
0977 
0978     ipc3_log_header(sdev->dev, "ipc rx", hdr.cmd);
0979 
0980     cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
0981 
0982     /* check message type */
0983     switch (cmd) {
0984     case SOF_IPC_GLB_REPLY:
0985         dev_err(sdev->dev, "ipc reply unknown\n");
0986         break;
0987     case SOF_IPC_FW_READY:
0988         /* check for FW boot completion */
0989         if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
0990             err = ipc3_fw_ready(sdev, cmd);
0991             if (err < 0)
0992                 sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
0993             else
0994                 sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK);
0995 
0996             /* wake up firmware loader */
0997             wake_up(&sdev->boot_wait);
0998         }
0999         break;
1000     case SOF_IPC_GLB_COMPOUND:
1001     case SOF_IPC_GLB_TPLG_MSG:
1002     case SOF_IPC_GLB_PM_MSG:
1003         break;
1004     case SOF_IPC_GLB_COMP_MSG:
1005         rx_callback = ipc3_comp_notification;
1006         break;
1007     case SOF_IPC_GLB_STREAM_MSG:
1008         rx_callback = ipc3_stream_message;
1009         break;
1010     case SOF_IPC_GLB_TRACE_MSG:
1011         rx_callback = ipc3_trace_message;
1012         break;
1013     default:
1014         dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd);
1015         break;
1016     }
1017 
1018     /* read the full message */
1019     msg_buf = kmalloc(hdr.size, GFP_KERNEL);
1020     if (!msg_buf)
1021         return;
1022 
1023     err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size);
1024     if (err < 0) {
1025         dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err);
1026     } else {
1027         /* Call local handler for the message */
1028         if (rx_callback)
1029             rx_callback(sdev, msg_buf);
1030 
1031         /* Notify registered clients */
1032         sof_client_ipc_rx_dispatcher(sdev, msg_buf);
1033     }
1034 
1035     kfree(msg_buf);
1036 
1037     ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd);
1038 }
1039 
1040 static int sof_ipc3_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
1041 {
1042     struct sof_ipc_pm_core_config core_cfg = {
1043         .hdr.size = sizeof(core_cfg),
1044         .hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
1045     };
1046     struct sof_ipc_reply reply;
1047 
1048     if (on)
1049         core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx);
1050     else
1051         core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx);
1052 
1053     return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg),
1054                    &reply, sizeof(reply), false);
1055 }
1056 
1057 static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
1058 {
1059     struct sof_ipc_pm_ctx pm_ctx = {
1060         .hdr.size = sizeof(pm_ctx),
1061         .hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd,
1062     };
1063     struct sof_ipc_reply reply;
1064 
1065     /* send ctx save ipc to dsp */
1066     return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx),
1067                    &reply, sizeof(reply), false);
1068 }
1069 
1070 static int sof_ipc3_ctx_save(struct snd_sof_dev *sdev)
1071 {
1072     return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
1073 }
1074 
1075 static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
1076 {
1077     return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
1078 }
1079 
1080 static const struct sof_ipc_pm_ops ipc3_pm_ops = {
1081     .ctx_save = sof_ipc3_ctx_save,
1082     .ctx_restore = sof_ipc3_ctx_restore,
1083     .set_core_state = sof_ipc3_set_core_state,
1084 };
1085 
1086 const struct sof_ipc_ops ipc3_ops = {
1087     .tplg = &ipc3_tplg_ops,
1088     .pm = &ipc3_pm_ops,
1089     .pcm = &ipc3_pcm_ops,
1090     .fw_loader = &ipc3_loader_ops,
1091     .fw_tracing = &ipc3_dtrace_ops,
1092 
1093     .tx_msg = sof_ipc3_tx_msg,
1094     .rx_msg = sof_ipc3_rx_msg,
1095     .set_get_data = sof_ipc3_set_get_data,
1096     .get_reply = sof_ipc3_get_reply,
1097 };