// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // // Copyright(c) 2022 Intel Corporation // // Authors: Rander Wang <rander.wang@linux.intel.com> // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> // #include <linux/firmware.h> #include <sound/sof/header.h> #include <sound/sof/ipc4/header.h> #include"sof-priv.h" #include"sof-audio.h" #include"ipc4-fw-reg.h" #include"ipc4-priv.h" #include"ipc4-telemetry.h" #include"ops.h"
staticconststruct sof_ipc4_fw_status { int status; char *msg;
} ipc4_status[] = {
{0, "The operation was successful"},
{1, "Invalid parameter specified"},
{2, "Unknown message type specified"},
{3, "Not enough space in the IPC reply buffer to complete the request"},
{4, "The system or resource is busy"},
{5, "Replaced ADSP IPC PENDING (unused)"},
{6, "Unknown error while processing the request"},
{7, "Unsupported operation requested"},
{8, "Reserved (ADSP_STAGE_UNINITIALIZED removed)"},
{9, "Specified resource not found"},
{10, "A resource's ID requested to be created is already assigned"},
{11, "Reserved (ADSP_IPC_OUT_OF_MIPS removed)"},
{12, "Required resource is in invalid state"},
{13, "Requested power transition failed to complete"},
{14, "Manifest of the library being loaded is invalid"},
{15, "Requested service or data is unavailable on the target platform"},
{42, "Library target address is out of storage memory range"},
{43, "Reserved"},
{44, "Image verification by CSE failed"},
{100, "General module management error"},
{101, "Module loading failed"},
{102, "Integrity check of the loaded module content failed"},
{103, "Attempt to unload code of the module in use"},
{104, "Other failure of module instance initialization request"},
{105, "Reserved (ADSP_IPC_OUT_OF_MIPS removed)"},
{106, "Reserved (ADSP_IPC_CONFIG_GET_ERROR removed)"},
{107, "Reserved (ADSP_IPC_CONFIG_SET_ERROR removed)"},
{108, "Reserved (ADSP_IPC_LARGE_CONFIG_GET_ERROR removed)"},
{109, "Reserved (ADSP_IPC_LARGE_CONFIG_SET_ERROR removed)"},
{110, "Invalid (out of range) module ID provided"},
{111, "Invalid module instance ID provided"},
{112, "Invalid queue (pin) ID provided"},
{113, "Invalid destination queue (pin) ID provided"},
{114, "Reserved (ADSP_IPC_BIND_UNBIND_DST_SINK_UNSUPPORTED removed)"},
{115, "Reserved (ADSP_IPC_UNLOAD_INST_EXISTS removed)"},
{116, "Invalid target code ID provided"},
{117, "Injection DMA buffer is too small for probing the input pin"},
{118, "Extraction DMA buffer is too small for probing the output pin"},
{120, "Invalid ID of configuration item provided in TLV list"},
{121, "Invalid length of configuration item provided in TLV list"},
{122, "Invalid structure of configuration item provided"},
{140, "Initialization of DMA Gateway failed"},
{141, "Invalid ID of gateway provided"},
{142, "Setting state of DMA Gateway failed"},
{143, "DMA_CONTROL message targeting gateway not allocated yet"},
{150, "Attempt to configure SCLK while I2S port is running"},
{151, "Attempt to configure MCLK while I2S port is running"},
{152, "Attempt to stop SCLK that is not running"},
{153, "Attempt to stop MCLK that is not running"},
{160, "Reserved (ADSP_IPC_PIPELINE_NOT_INITIALIZED removed)"},
{161, "Reserved (ADSP_IPC_PIPELINE_NOT_EXIST removed)"},
{162, "Reserved (ADSP_IPC_PIPELINE_SAVE_FAILED removed)"},
{163, "Reserved (ADSP_IPC_PIPELINE_RESTORE_FAILED removed)"},
{165, "Reserved (ADSP_IPC_PIPELINE_ALREADY_EXISTS removed)"},
};
staticint sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status)
{ int i, ret;
status &= SOF_IPC4_REPLY_STATUS;
if (!status) return 0;
for (i = 0; i < ARRAY_SIZE(ipc4_status); i++) { if (ipc4_status[i].status == status) {
dev_err(sdev->dev, "FW reported error: %u - %s\n",
status, ipc4_status[i].msg); goto to_errno;
}
}
if (i == ARRAY_SIZE(ipc4_status))
dev_err(sdev->dev, "FW reported error: %u - Unknown\n", status);
to_errno: switch (status) { case 2: case 15:
ret = -EOPNOTSUPP; break; case 8: case 11: case 105 ... 109: case 114 ... 115: case 160 ... 163: case 165:
ret = -ENOENT; break; case 4: case 150: case 151:
ret = -EBUSY; break; default:
ret = -EINVAL; break;
}
/* Do not print log buffer notification if not desired */ if (notif == SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS &&
!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) return;
if (notif < SOF_IPC4_NOTIFY_TYPE_LAST)
str2 = ipc4_dbg_notification_type[notif]; if (!str2)
str2 = "Unknown Global notification";
}
}
ret = sof_ipc4_check_reply_status(sdev, ipc4_reply->primary); if (ret) return ret;
/* No other information is expected for non large config get replies */ if (!msg->reply_size || !SOF_IPC4_MSG_IS_MODULE_MSG(ipc4_reply->primary) ||
(SOF_IPC4_MSG_TYPE_GET(ipc4_reply->primary) != SOF_IPC4_MOD_LARGE_CONFIG_GET)) return 0;
/* Read the requested payload */
snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, ipc4_reply->data_ptr,
msg->reply_size);
/* Send the message for the current chunk */
ret = ipc4_tx_msg_unlocked(sdev->ipc, &tx, tx_size, &rx, rx_size); if (ret < 0) {
dev_err(sdev->dev, "%s: large config %s failed at offset %zu: %d\n",
__func__, set ? "set" : "get", offset, ret); goto out;
}
if (!set && rx.extension & SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK_MASK) { /* Verify the firmware reported total payload size */
rx_size = rx.extension & SOF_IPC4_MOD_EXT_MSG_SIZE_MASK;
if (rx_size > payload_bytes) {
dev_err(sdev->dev, "%s: Receive buffer (%zu) is too small for %zu\n",
__func__, payload_bytes, rx_size);
ret = -ENOMEM; goto out;
}
/* TODO: get max_payload_size from firmware */
sdev->ipc->max_payload_size = SOF_IPC4_MSG_MAX_SIZE;
/* Allocate memory for the ipc4 container and the maximum payload */
msg->reply_data = devm_kzalloc(sdev->dev, sdev->ipc->max_payload_size + sizeof(struct sof_ipc4_msg), GFP_KERNEL); if (!msg->reply_data) return -ENOMEM;
/* The type is the second u32 in the slot descriptor */
slot_desc_type_offset = sdev->debug_box.offset + sizeof(u32); for (i = 0; i < SOF_IPC4_MAX_DEBUG_SLOTS; i++) {
sof_mailbox_read(sdev, slot_desc_type_offset, &type, sizeof(type));
if (type == slot_type) return sdev->debug_box.offset + (i + 1) * SOF_IPC4_DEBUG_SLOT_SIZE;
/* * After the initial boot only check if the libraries have been * restored when full context save is not enabled
*/ if (!ipc4_data->fw_context_save)
ipc4_data->libraries_restored = !!(ipc4_msg->primary &
SOF_IPC4_FW_READY_LIB_RESTORED);
/* * If the notification includes additional, module specific data, then * we need to re-allocate the buffer and re-read the whole payload, * including the event_data
*/ if (data->event_data_size) { void *new; int ret;
ipc4_msg->data_size += data->event_data_size;
new = krealloc(ipc4_msg->data_ptr, ipc4_msg->data_size, GFP_KERNEL); if (!new) {
ipc4_msg->data_size -= data->event_data_size; return;
}
/* re-read the whole payload */
ipc4_msg->data_ptr = new;
ret = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr,
ipc4_msg->data_size); if (ret < 0) {
dev_err(sdev->dev, "Failed to read the full module notification: %d\n",
ret); return;
}
data = ipc4_msg->data_ptr;
}
/* * The context save callback is used to send a message to the firmware notifying * it that the primary core is going to be turned off, which is used as an * indication to prepare for a full power down, thus preparing for IMR boot * (when supported) * * Note: in IPC4 there is no message used to restore context, thus no context * restore callback is implemented
*/ staticint sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
{ return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
}
/* Set up the windows for IPC communication */
inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev); if (inbox_offset < 0) {
dev_err(sdev->dev, "%s: No mailbox offset\n", __func__); return inbox_offset;
}
xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) { /* * The basefw (ID == 0) is handled by generic code, it is not * loaded by IPC4 code.
*/ if (lib_id != 0)
release_firmware(fw_lib->sof_fw.fw);
fw_lib->sof_fw.fw = NULL;
}
xa_destroy(&ipc4_data->fw_lib_xa);
}
staticint sof_ipc4_post_boot(struct snd_sof_dev *sdev)
{ if (sdev->first_boot) { int ret = sof_ipc4_complete_split_release(sdev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.