0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <sound/sof/header.h>
0012 #include <sound/sof/ipc4/header.h>
0013 #include "sof-priv.h"
0014 #include "sof-audio.h"
0015 #include "ipc4-priv.h"
0016 #include "ops.h"
0017
0018 #ifdef DEBUG_VERBOSE
0019 #define sof_ipc4_dump_payload(sdev, ipc_data, size) \
0020 print_hex_dump_debug("Message payload: ", \
0021 DUMP_PREFIX_OFFSET, \
0022 16, 4, ipc_data, size, false)
0023 #else
0024 #define sof_ipc4_dump_payload(sdev, ipc_data, size) do { } while (0)
0025 #endif
0026
0027 static const struct sof_ipc4_fw_status {
0028 int status;
0029 char *msg;
0030 } ipc4_status[] = {
0031 {0, "The operation was successful"},
0032 {1, "Invalid parameter specified"},
0033 {2, "Unknown message type specified"},
0034 {3, "Not enough space in the IPC reply buffer to complete the request"},
0035 {4, "The system or resource is busy"},
0036 {5, "Replaced ADSP IPC PENDING (unused)"},
0037 {6, "Unknown error while processing the request"},
0038 {7, "Unsupported operation requested"},
0039 {8, "Reserved (ADSP_STAGE_UNINITIALIZED removed)"},
0040 {9, "Specified resource not found"},
0041 {10, "A resource's ID requested to be created is already assigned"},
0042 {11, "Reserved (ADSP_IPC_OUT_OF_MIPS removed)"},
0043 {12, "Required resource is in invalid state"},
0044 {13, "Requested power transition failed to complete"},
0045 {14, "Manifest of the library being loaded is invalid"},
0046 {15, "Requested service or data is unavailable on the target platform"},
0047 {42, "Library target address is out of storage memory range"},
0048 {43, "Reserved"},
0049 {44, "Image verification by CSE failed"},
0050 {100, "General module management error"},
0051 {101, "Module loading failed"},
0052 {102, "Integrity check of the loaded module content failed"},
0053 {103, "Attempt to unload code of the module in use"},
0054 {104, "Other failure of module instance initialization request"},
0055 {105, "Reserved (ADSP_IPC_OUT_OF_MIPS removed)"},
0056 {106, "Reserved (ADSP_IPC_CONFIG_GET_ERROR removed)"},
0057 {107, "Reserved (ADSP_IPC_CONFIG_SET_ERROR removed)"},
0058 {108, "Reserved (ADSP_IPC_LARGE_CONFIG_GET_ERROR removed)"},
0059 {109, "Reserved (ADSP_IPC_LARGE_CONFIG_SET_ERROR removed)"},
0060 {110, "Invalid (out of range) module ID provided"},
0061 {111, "Invalid module instance ID provided"},
0062 {112, "Invalid queue (pin) ID provided"},
0063 {113, "Invalid destination queue (pin) ID provided"},
0064 {114, "Reserved (ADSP_IPC_BIND_UNBIND_DST_SINK_UNSUPPORTED removed)"},
0065 {115, "Reserved (ADSP_IPC_UNLOAD_INST_EXISTS removed)"},
0066 {116, "Invalid target code ID provided"},
0067 {117, "Injection DMA buffer is too small for probing the input pin"},
0068 {118, "Extraction DMA buffer is too small for probing the output pin"},
0069 {120, "Invalid ID of configuration item provided in TLV list"},
0070 {121, "Invalid length of configuration item provided in TLV list"},
0071 {122, "Invalid structure of configuration item provided"},
0072 {140, "Initialization of DMA Gateway failed"},
0073 {141, "Invalid ID of gateway provided"},
0074 {142, "Setting state of DMA Gateway failed"},
0075 {143, "DMA_CONTROL message targeting gateway not allocated yet"},
0076 {150, "Attempt to configure SCLK while I2S port is running"},
0077 {151, "Attempt to configure MCLK while I2S port is running"},
0078 {152, "Attempt to stop SCLK that is not running"},
0079 {153, "Attempt to stop MCLK that is not running"},
0080 {160, "Reserved (ADSP_IPC_PIPELINE_NOT_INITIALIZED removed)"},
0081 {161, "Reserved (ADSP_IPC_PIPELINE_NOT_EXIST removed)"},
0082 {162, "Reserved (ADSP_IPC_PIPELINE_SAVE_FAILED removed)"},
0083 {163, "Reserved (ADSP_IPC_PIPELINE_RESTORE_FAILED removed)"},
0084 {165, "Reserved (ADSP_IPC_PIPELINE_ALREADY_EXISTS removed)"},
0085 };
0086
0087 static int sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status)
0088 {
0089 int i, ret;
0090
0091 status &= SOF_IPC4_REPLY_STATUS;
0092
0093 if (!status)
0094 return 0;
0095
0096 for (i = 0; i < ARRAY_SIZE(ipc4_status); i++) {
0097 if (ipc4_status[i].status == status) {
0098 dev_err(sdev->dev, "FW reported error: %u - %s\n",
0099 status, ipc4_status[i].msg);
0100 goto to_errno;
0101 }
0102 }
0103
0104 if (i == ARRAY_SIZE(ipc4_status))
0105 dev_err(sdev->dev, "FW reported error: %u - Unknown\n", status);
0106
0107 to_errno:
0108 switch (status) {
0109 case 8:
0110 case 11:
0111 case 105 ... 109:
0112 case 114 ... 115:
0113 case 160 ... 163:
0114 case 165:
0115 ret = -ENOENT;
0116 break;
0117 case 4:
0118 case 150:
0119 case 151:
0120 ret = -EBUSY;
0121 break;
0122 default:
0123 ret = -EINVAL;
0124 break;
0125 }
0126
0127 return ret;
0128 }
0129
0130 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
0131 #define DBG_IPC4_MSG_TYPE_ENTRY(type) [SOF_IPC4_##type] = #type
0132 static const char * const ipc4_dbg_mod_msg_type[] = {
0133 DBG_IPC4_MSG_TYPE_ENTRY(MOD_INIT_INSTANCE),
0134 DBG_IPC4_MSG_TYPE_ENTRY(MOD_CONFIG_GET),
0135 DBG_IPC4_MSG_TYPE_ENTRY(MOD_CONFIG_SET),
0136 DBG_IPC4_MSG_TYPE_ENTRY(MOD_LARGE_CONFIG_GET),
0137 DBG_IPC4_MSG_TYPE_ENTRY(MOD_LARGE_CONFIG_SET),
0138 DBG_IPC4_MSG_TYPE_ENTRY(MOD_BIND),
0139 DBG_IPC4_MSG_TYPE_ENTRY(MOD_UNBIND),
0140 DBG_IPC4_MSG_TYPE_ENTRY(MOD_SET_DX),
0141 DBG_IPC4_MSG_TYPE_ENTRY(MOD_SET_D0IX),
0142 DBG_IPC4_MSG_TYPE_ENTRY(MOD_ENTER_MODULE_RESTORE),
0143 DBG_IPC4_MSG_TYPE_ENTRY(MOD_EXIT_MODULE_RESTORE),
0144 DBG_IPC4_MSG_TYPE_ENTRY(MOD_DELETE_INSTANCE),
0145 };
0146
0147 static const char * const ipc4_dbg_glb_msg_type[] = {
0148 DBG_IPC4_MSG_TYPE_ENTRY(GLB_BOOT_CONFIG),
0149 DBG_IPC4_MSG_TYPE_ENTRY(GLB_ROM_CONTROL),
0150 DBG_IPC4_MSG_TYPE_ENTRY(GLB_IPCGATEWAY_CMD),
0151 DBG_IPC4_MSG_TYPE_ENTRY(GLB_PERF_MEASUREMENTS_CMD),
0152 DBG_IPC4_MSG_TYPE_ENTRY(GLB_CHAIN_DMA),
0153 DBG_IPC4_MSG_TYPE_ENTRY(GLB_LOAD_MULTIPLE_MODULES),
0154 DBG_IPC4_MSG_TYPE_ENTRY(GLB_UNLOAD_MULTIPLE_MODULES),
0155 DBG_IPC4_MSG_TYPE_ENTRY(GLB_CREATE_PIPELINE),
0156 DBG_IPC4_MSG_TYPE_ENTRY(GLB_DELETE_PIPELINE),
0157 DBG_IPC4_MSG_TYPE_ENTRY(GLB_SET_PIPELINE_STATE),
0158 DBG_IPC4_MSG_TYPE_ENTRY(GLB_GET_PIPELINE_STATE),
0159 DBG_IPC4_MSG_TYPE_ENTRY(GLB_GET_PIPELINE_CONTEXT_SIZE),
0160 DBG_IPC4_MSG_TYPE_ENTRY(GLB_SAVE_PIPELINE),
0161 DBG_IPC4_MSG_TYPE_ENTRY(GLB_RESTORE_PIPELINE),
0162 DBG_IPC4_MSG_TYPE_ENTRY(GLB_LOAD_LIBRARY),
0163 DBG_IPC4_MSG_TYPE_ENTRY(GLB_INTERNAL_MESSAGE),
0164 DBG_IPC4_MSG_TYPE_ENTRY(GLB_NOTIFICATION),
0165 };
0166
0167 #define DBG_IPC4_NOTIFICATION_TYPE_ENTRY(type) [SOF_IPC4_NOTIFY_##type] = #type
0168 static const char * const ipc4_dbg_notification_type[] = {
0169 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(PHRASE_DETECTED),
0170 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(RESOURCE_EVENT),
0171 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(LOG_BUFFER_STATUS),
0172 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(TIMESTAMP_CAPTURED),
0173 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(FW_READY),
0174 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(FW_AUD_CLASS_RESULT),
0175 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(EXCEPTION_CAUGHT),
0176 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(MODULE_NOTIFICATION),
0177 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(PROBE_DATA_AVAILABLE),
0178 DBG_IPC4_NOTIFICATION_TYPE_ENTRY(ASYNC_MSG_SRVC_MESSAGE),
0179 };
0180
0181 static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_msg *msg,
0182 bool data_size_valid)
0183 {
0184 u32 val, type;
0185 const u8 *str2 = NULL;
0186 const u8 *str = NULL;
0187
0188 val = msg->primary & SOF_IPC4_MSG_TARGET_MASK;
0189 type = SOF_IPC4_MSG_TYPE_GET(msg->primary);
0190
0191 if (val == SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG)) {
0192
0193 if (type < SOF_IPC4_MOD_TYPE_LAST)
0194 str = ipc4_dbg_mod_msg_type[type];
0195 if (!str)
0196 str = "Unknown Module message type";
0197 } else {
0198
0199 if (type < SOF_IPC4_GLB_TYPE_LAST)
0200 str = ipc4_dbg_glb_msg_type[type];
0201 if (!str)
0202 str = "Unknown Global message type";
0203
0204 if (type == SOF_IPC4_GLB_NOTIFICATION) {
0205
0206 u32 notif = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary);
0207
0208 if (notif < SOF_IPC4_NOTIFY_TYPE_LAST)
0209 str2 = ipc4_dbg_notification_type[notif];
0210 if (!str2)
0211 str2 = "Unknown Global notification";
0212 }
0213 }
0214
0215 if (str2) {
0216 if (data_size_valid && msg->data_size)
0217 dev_dbg(dev, "%s: %#x|%#x: %s|%s [data size: %zu]\n",
0218 text, msg->primary, msg->extension, str, str2,
0219 msg->data_size);
0220 else
0221 dev_dbg(dev, "%s: %#x|%#x: %s|%s\n", text, msg->primary,
0222 msg->extension, str, str2);
0223 } else {
0224 if (data_size_valid && msg->data_size)
0225 dev_dbg(dev, "%s: %#x|%#x: %s [data size: %zu]\n",
0226 text, msg->primary, msg->extension, str,
0227 msg->data_size);
0228 else
0229 dev_dbg(dev, "%s: %#x|%#x: %s\n", text, msg->primary,
0230 msg->extension, str);
0231 }
0232 }
0233 #else
0234 static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_msg *msg,
0235 bool data_size_valid)
0236 {
0237 if (data_size_valid && msg->data_size)
0238 dev_dbg(dev, "%s: %#x|%#x [data size: %zu]\n", text,
0239 msg->primary, msg->extension, msg->data_size);
0240 else
0241 dev_dbg(dev, "%s: %#x|%#x\n", text, msg->primary, msg->extension);
0242 }
0243 #endif
0244
0245 static int sof_ipc4_get_reply(struct snd_sof_dev *sdev)
0246 {
0247 struct snd_sof_ipc_msg *msg = sdev->msg;
0248 struct sof_ipc4_msg *ipc4_reply;
0249 int ret;
0250
0251
0252 ipc4_reply = msg->reply_data;
0253
0254 sof_ipc4_log_header(sdev->dev, "ipc tx reply", ipc4_reply, false);
0255
0256 ret = sof_ipc4_check_reply_status(sdev, ipc4_reply->primary);
0257 if (ret)
0258 return ret;
0259
0260
0261 if (!msg->reply_size || !SOF_IPC4_MSG_IS_MODULE_MSG(ipc4_reply->primary) ||
0262 (SOF_IPC4_MSG_TYPE_GET(ipc4_reply->primary) != SOF_IPC4_MOD_LARGE_CONFIG_GET))
0263 return 0;
0264
0265
0266 snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, ipc4_reply->data_ptr,
0267 msg->reply_size);
0268
0269 return 0;
0270 }
0271
0272
0273 static int ipc4_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
0274 {
0275 struct snd_sof_ipc_msg *msg = &ipc->msg;
0276 struct sof_ipc4_msg *ipc4_msg = msg->msg_data;
0277 struct snd_sof_dev *sdev = ipc->sdev;
0278 int ret;
0279
0280
0281 ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
0282 msecs_to_jiffies(sdev->ipc_timeout));
0283 if (ret == 0) {
0284 dev_err(sdev->dev, "ipc timed out for %#x|%#x\n",
0285 ipc4_msg->primary, ipc4_msg->extension);
0286 return -ETIMEDOUT;
0287 }
0288
0289 if (msg->reply_error) {
0290 dev_err(sdev->dev, "ipc error for msg %#x|%#x\n",
0291 ipc4_msg->primary, ipc4_msg->extension);
0292 ret = msg->reply_error;
0293 } else {
0294 if (reply_data) {
0295 struct sof_ipc4_msg *ipc4_reply = msg->reply_data;
0296 struct sof_ipc4_msg *ipc4_reply_data = reply_data;
0297
0298
0299 ipc4_reply_data->header_u64 = ipc4_reply->header_u64;
0300 if (msg->reply_size && ipc4_reply_data->data_ptr) {
0301
0302 memcpy(ipc4_reply_data->data_ptr, ipc4_reply->data_ptr,
0303 msg->reply_size);
0304 ipc4_reply_data->data_size = msg->reply_size;
0305 }
0306 }
0307
0308 ret = 0;
0309 sof_ipc4_log_header(sdev->dev, "ipc tx done ", ipc4_msg, true);
0310 }
0311
0312
0313 if (sdev->ipc_dump_printed) {
0314 sdev->dbg_dump_printed = false;
0315 sdev->ipc_dump_printed = false;
0316 }
0317
0318 return ret;
0319 }
0320
0321 static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
0322 void *msg_data, size_t msg_bytes,
0323 void *reply_data, size_t reply_bytes)
0324 {
0325 struct sof_ipc4_msg *ipc4_msg = msg_data;
0326 struct snd_sof_dev *sdev = ipc->sdev;
0327 int ret;
0328
0329 if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size)
0330 return -EINVAL;
0331
0332 ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
0333 if (ret) {
0334 dev_err_ratelimited(sdev->dev,
0335 "%s: ipc message send for %#x|%#x failed: %d\n",
0336 __func__, ipc4_msg->primary, ipc4_msg->extension, ret);
0337 return ret;
0338 }
0339
0340 sof_ipc4_log_header(sdev->dev, "ipc tx ", msg_data, true);
0341
0342
0343 return ipc4_wait_tx_done(ipc, reply_data);
0344 }
0345
0346 static int sof_ipc4_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 #ifdef DEBUG_VERBOSE
0351 struct sof_ipc4_msg *msg = NULL;
0352 #endif
0353 int ret;
0354
0355 if (!msg_data)
0356 return -EINVAL;
0357
0358
0359 mutex_lock(&ipc->tx_mutex);
0360
0361 ret = ipc4_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes);
0362
0363 mutex_unlock(&ipc->tx_mutex);
0364
0365 #ifdef DEBUG_VERBOSE
0366
0367 if (msg_bytes)
0368 msg = msg_data;
0369 else if (reply_bytes)
0370 msg = reply_data;
0371
0372 if (msg)
0373 sof_ipc4_dump_payload(sdev, msg->data_ptr, msg->data_size);
0374 #endif
0375
0376 return ret;
0377 }
0378
0379 static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
0380 size_t payload_bytes, bool set)
0381 {
0382 size_t payload_limit = sdev->ipc->max_payload_size;
0383 struct sof_ipc4_msg *ipc4_msg = data;
0384 struct sof_ipc4_msg tx = {{ 0 }};
0385 struct sof_ipc4_msg rx = {{ 0 }};
0386 size_t remaining = payload_bytes;
0387 size_t offset = 0;
0388 size_t chunk_size;
0389 int ret;
0390
0391 if (!data)
0392 return -EINVAL;
0393
0394 if ((ipc4_msg->primary & SOF_IPC4_MSG_TARGET_MASK) !=
0395 SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG))
0396 return -EINVAL;
0397
0398 ipc4_msg->primary &= ~SOF_IPC4_MSG_TYPE_MASK;
0399 tx.primary = ipc4_msg->primary;
0400 tx.extension = ipc4_msg->extension;
0401
0402 if (set)
0403 tx.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
0404 else
0405 tx.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_GET);
0406
0407 tx.extension &= ~SOF_IPC4_MOD_EXT_MSG_SIZE_MASK;
0408 tx.extension |= SOF_IPC4_MOD_EXT_MSG_SIZE(payload_bytes);
0409
0410 tx.extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
0411
0412
0413 mutex_lock(&sdev->ipc->tx_mutex);
0414
0415 do {
0416 size_t tx_size, rx_size;
0417
0418 if (remaining > payload_limit) {
0419 chunk_size = payload_limit;
0420 } else {
0421 chunk_size = remaining;
0422 if (set)
0423 tx.extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1);
0424 }
0425
0426 if (offset) {
0427 tx.extension &= ~SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK_MASK;
0428 tx.extension &= ~SOF_IPC4_MOD_EXT_MSG_SIZE_MASK;
0429 tx.extension |= SOF_IPC4_MOD_EXT_MSG_SIZE(offset);
0430 }
0431
0432 if (set) {
0433 tx.data_size = chunk_size;
0434 tx.data_ptr = ipc4_msg->data_ptr + offset;
0435
0436 tx_size = chunk_size;
0437 rx_size = 0;
0438 } else {
0439 rx.primary = 0;
0440 rx.extension = 0;
0441 rx.data_size = chunk_size;
0442 rx.data_ptr = ipc4_msg->data_ptr + offset;
0443
0444 tx_size = 0;
0445 rx_size = chunk_size;
0446 }
0447
0448
0449 ret = ipc4_tx_msg_unlocked(sdev->ipc, &tx, tx_size, &rx, rx_size);
0450 if (ret < 0) {
0451 dev_err(sdev->dev,
0452 "%s: large config %s failed at offset %zu: %d\n",
0453 __func__, set ? "set" : "get", offset, ret);
0454 goto out;
0455 }
0456
0457 if (!set && rx.extension & SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK_MASK) {
0458
0459 rx_size = rx.extension & SOF_IPC4_MOD_EXT_MSG_SIZE_MASK;
0460
0461 if (rx_size > payload_bytes) {
0462 dev_err(sdev->dev,
0463 "%s: Receive buffer (%zu) is too small for %zu\n",
0464 __func__, payload_bytes, rx_size);
0465 ret = -ENOMEM;
0466 goto out;
0467 }
0468
0469 if (rx_size < chunk_size) {
0470 chunk_size = rx_size;
0471 remaining = rx_size;
0472 } else if (rx_size < payload_bytes) {
0473 remaining = rx_size;
0474 }
0475 }
0476
0477 offset += chunk_size;
0478 remaining -= chunk_size;
0479 } while (remaining);
0480
0481
0482 if (!set && payload_bytes != offset)
0483 ipc4_msg->data_size = offset;
0484
0485 sof_ipc4_dump_payload(sdev, ipc4_msg->data_ptr, ipc4_msg->data_size);
0486
0487 out:
0488 mutex_unlock(&sdev->ipc->tx_mutex);
0489
0490 return ret;
0491 }
0492
0493 static int sof_ipc4_init_msg_memory(struct snd_sof_dev *sdev)
0494 {
0495 struct sof_ipc4_msg *ipc4_msg;
0496 struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
0497
0498
0499 sdev->ipc->max_payload_size = SOF_IPC4_MSG_MAX_SIZE;
0500
0501
0502 msg->reply_data = devm_kzalloc(sdev->dev, sdev->ipc->max_payload_size +
0503 sizeof(struct sof_ipc4_msg), GFP_KERNEL);
0504 if (!msg->reply_data)
0505 return -ENOMEM;
0506
0507 ipc4_msg = msg->reply_data;
0508 ipc4_msg->data_ptr = msg->reply_data + sizeof(struct sof_ipc4_msg);
0509
0510 return 0;
0511 }
0512
0513 static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg)
0514 {
0515 int inbox_offset, inbox_size, outbox_offset, outbox_size;
0516
0517
0518 if (!sdev->first_boot)
0519 return 0;
0520
0521
0522 inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev);
0523 if (inbox_offset < 0) {
0524 dev_err(sdev->dev, "%s: No mailbox offset\n", __func__);
0525 return inbox_offset;
0526 }
0527 inbox_size = SOF_IPC4_MSG_MAX_SIZE;
0528 outbox_offset = snd_sof_dsp_get_window_offset(sdev, 1);
0529 outbox_size = SOF_IPC4_MSG_MAX_SIZE;
0530
0531 sdev->dsp_box.offset = inbox_offset;
0532 sdev->dsp_box.size = inbox_size;
0533 sdev->host_box.offset = outbox_offset;
0534 sdev->host_box.size = outbox_size;
0535
0536 dev_dbg(sdev->dev, "mailbox upstream 0x%x - size 0x%x\n",
0537 inbox_offset, inbox_size);
0538 dev_dbg(sdev->dev, "mailbox downstream 0x%x - size 0x%x\n",
0539 outbox_offset, outbox_size);
0540
0541 return sof_ipc4_init_msg_memory(sdev);
0542 }
0543
0544 static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
0545 {
0546 struct sof_ipc4_msg *ipc4_msg = sdev->ipc->msg.rx_data;
0547 size_t data_size = 0;
0548 int err;
0549
0550 if (!ipc4_msg || !SOF_IPC4_MSG_IS_NOTIFICATION(ipc4_msg->primary))
0551 return;
0552
0553 ipc4_msg->data_ptr = NULL;
0554 ipc4_msg->data_size = 0;
0555
0556 sof_ipc4_log_header(sdev->dev, "ipc rx ", ipc4_msg, false);
0557
0558 switch (SOF_IPC4_NOTIFICATION_TYPE_GET(ipc4_msg->primary)) {
0559 case SOF_IPC4_NOTIFY_FW_READY:
0560
0561 if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
0562 err = ipc4_fw_ready(sdev, ipc4_msg);
0563 if (err < 0)
0564 sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
0565 else
0566 sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK);
0567
0568
0569 wake_up(&sdev->boot_wait);
0570 }
0571
0572 break;
0573 case SOF_IPC4_NOTIFY_RESOURCE_EVENT:
0574 data_size = sizeof(struct sof_ipc4_notify_resource_data);
0575 break;
0576 default:
0577 dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n",
0578 ipc4_msg->primary, ipc4_msg->extension);
0579 break;
0580 }
0581
0582 if (data_size) {
0583 ipc4_msg->data_ptr = kmalloc(data_size, GFP_KERNEL);
0584 if (!ipc4_msg->data_ptr)
0585 return;
0586
0587 ipc4_msg->data_size = data_size;
0588 snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size);
0589 }
0590
0591 sof_ipc4_log_header(sdev->dev, "ipc rx done ", ipc4_msg, true);
0592
0593 if (data_size) {
0594 kfree(ipc4_msg->data_ptr);
0595 ipc4_msg->data_ptr = NULL;
0596 ipc4_msg->data_size = 0;
0597 }
0598 }
0599
0600 static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
0601 {
0602 struct sof_ipc4_dx_state_info dx_state;
0603 struct sof_ipc4_msg msg;
0604
0605 dx_state.core_mask = BIT(core_idx);
0606 if (on)
0607 dx_state.dx_mask = BIT(core_idx);
0608 else
0609 dx_state.dx_mask = 0;
0610
0611 msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX);
0612 msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
0613 msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
0614 msg.extension = 0;
0615 msg.data_ptr = &dx_state;
0616 msg.data_size = sizeof(dx_state);
0617
0618 return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false);
0619 }
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630 static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
0631 {
0632 return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
0633 }
0634
0635 static const struct sof_ipc_pm_ops ipc4_pm_ops = {
0636 .ctx_save = sof_ipc4_ctx_save,
0637 .set_core_state = sof_ipc4_set_core_state,
0638 };
0639
0640 const struct sof_ipc_ops ipc4_ops = {
0641 .tx_msg = sof_ipc4_tx_msg,
0642 .rx_msg = sof_ipc4_rx_msg,
0643 .set_get_data = sof_ipc4_set_get_data,
0644 .get_reply = sof_ipc4_get_reply,
0645 .pm = &ipc4_pm_ops,
0646 .fw_loader = &ipc4_loader_ops,
0647 .tplg = &ipc4_tplg_ops,
0648 .pcm = &ipc4_pcm_ops,
0649 };