0001
0002
0003
0004
0005
0006
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
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
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
0269
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
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
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
0308 memcpy(reply_data, msg->reply_data,
0309 msg->reply_size);
0310 }
0311
0312
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
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
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
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
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
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
0445 memcpy(cdata_chunk, cdata, hdr_bytes);
0446
0447
0448 mutex_lock(&sdev->ipc->tx_mutex);
0449
0450
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
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
0528
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
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
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
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
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
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
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
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
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
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
0804 if (!sdev->first_boot)
0805 return 0;
0806
0807
0808
0809
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
0820 ret = sof_ipc3_validate_fw_version(sdev);
0821 if (ret < 0)
0822 return ret;
0823
0824
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
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
0865 snd_sof_pcm_period_elapsed(stream->substream);
0866 }
0867
0868
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
0896 memcpy(&stream->posn, &posn, sizeof(posn));
0897 snd_pcm_stop_xrun(stream->substream);
0898 #endif
0899 }
0900
0901
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
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
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
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
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
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
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
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
1028 if (rx_callback)
1029 rx_callback(sdev, msg_buf);
1030
1031
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
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 };