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) 2022 Intel Corporation. All rights reserved.
0007 //
0008 // Authors: Rander Wang <rander.wang@linux.intel.com>
0009 //      Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
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         /* Module message */
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         /* Global FW message */
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             /* Notification message */
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 /* CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC */
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     /* get the generic reply */
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     /* No other information is expected for non large config get replies */
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     /* Read the requested payload */
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 /* wait for IPC message reply */
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     /* wait for DSP IPC completion */
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             /* Copy the header */
0299             ipc4_reply_data->header_u64 = ipc4_reply->header_u64;
0300             if (msg->reply_size && ipc4_reply_data->data_ptr) {
0301                 /* copy the payload returned from DSP */
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     /* 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     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     /* now wait for completion */
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     /* Serialise IPC TX */
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     /* payload is indicated by non zero msg/reply_bytes */
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     /* Serialise IPC TX */
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         /* Send the message for the current chunk */
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             /* Verify the firmware reported total payload size */
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     /* Adjust the received data size if needed */
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     /* TODO: get max_payload_size from firmware */
0499     sdev->ipc->max_payload_size = SOF_IPC4_MSG_MAX_SIZE;
0500 
0501     /* Allocate memory for the ipc4 container and the maximum payload */
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     /* no need to re-check version/ABI for subsequent boots */
0518     if (!sdev->first_boot)
0519         return 0;
0520 
0521     /* Set up the windows for IPC communication */
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         /* check for FW boot completion */
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             /* wake up firmware loader */
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  * The context save callback is used to send a message to the firmware notifying
0623  * it that the primary core is going to be turned off, which is used as an
0624  * indication to prepare for a full power down, thus preparing for IMR boot
0625  * (when supported)
0626  *
0627  * Note: in IPC4 there is no message used to restore context, thus no context
0628  * restore callback is implemented
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 };