// 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) 2021 Intel Corporation // //
staticvoid sof_ipc3_dump_payload(struct snd_sof_dev *sdev, void *ipc_data, size_t size)
{
dev_dbg(sdev->dev, "Size of payload following the header: %zu\n", size);
print_hex_dump_debug("Message payload: ", DUMP_PREFIX_OFFSET,
16, 4, ipc_data, size, false);
}
staticint sof_ipc3_get_reply(struct snd_sof_dev *sdev)
{ struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply *reply; int ret = 0;
/* get the generic reply */
reply = msg->reply_data;
snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply));
if (reply->error < 0) return reply->error;
if (!reply->hdr.size) { /* Reply should always be >= sizeof(struct sof_ipc_reply) */ if (msg->reply_size)
dev_err(sdev->dev, "empty reply received, expected %zu bytes\n",
msg->reply_size); else
dev_err(sdev->dev, "empty reply received\n");
return -EINVAL;
}
if (msg->reply_size > 0) { if (reply->hdr.size == msg->reply_size) {
ret = 0;
} elseif (reply->hdr.size < msg->reply_size) {
dev_dbg(sdev->dev, "reply size (%u) is less than expected (%zu)\n",
reply->hdr.size, msg->reply_size);
msg->reply_size = reply->hdr.size;
ret = 0;
} else {
dev_err(sdev->dev, "reply size (%u) exceeds the buffer size (%zu)\n",
reply->hdr.size, msg->reply_size);
ret = -EINVAL;
}
/* * get the full message if reply->hdr.size <= msg->reply_size * and the reply->hdr.size > sizeof(struct sof_ipc_reply)
*/ if (!ret && msg->reply_size > sizeof(*reply))
snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset,
msg->reply_data, msg->reply_size);
}
/* ensure the DSP is in D0 before sending a new IPC */
ret = snd_sof_dsp_set_power_state(sdev, &target_state); if (ret < 0) {
dev_err(sdev->dev, "%s: resuming DSP failed: %d\n",
__func__, ret); return ret;
}
}
if (!cdata || data_bytes < sizeof(*cdata)) return -EINVAL;
if ((cdata->rhdr.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_COMP_MSG) {
dev_err(sdev->dev, "%s: Not supported message type of %#x\n",
__func__, cdata->rhdr.hdr.cmd); return -EINVAL;
}
/* send normal size ipc in one part */ if (cdata->rhdr.hdr.size <= ipc->max_payload_size) return sof_ipc3_tx_msg(sdev, cdata, cdata->rhdr.hdr.size,
cdata, cdata->rhdr.hdr.size, false);
cdata_chunk = kzalloc(ipc->max_payload_size, GFP_KERNEL); if (!cdata_chunk) return -ENOMEM;
if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) return -EINVAL;
if (sdev->info_window) { if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
dev_err(sdev->dev, "mismatch between window descriptor from extended manifest and mailbox"); return -EINVAL;
} return 0;
}
/* keep a local copy of the data */
sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, GFP_KERNEL); if (!sdev->info_window) return -ENOMEM;
return 0;
}
int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev, conststruct sof_ipc_ext_data_hdr *ext_hdr)
{ int ret;
if (sdev->cc_version) { if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
dev_err(sdev->dev, "Receive diverged cc_version descriptions"); return -EINVAL;
} return 0;
}
dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
cc->name, cc->major, cc->minor, cc->micro, cc->desc, cc->optim);
/* create read-only cc_version debugfs to store compiler version info */ /* use local copy of the cc_version to prevent data corruption */ if (sdev->first_boot) {
sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL); if (!sdev->cc_version) return -ENOMEM;
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
cc->ext_hdr.hdr.size, "cc_version", 0444);
/* errors are only due to memory allocation, not debugfs */ if (ret < 0) {
dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n"); return ret;
}
}
return 0;
}
/* parse the extended FW boot data structures from FW boot message */ staticint ipc3_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
{ struct sof_ipc_ext_data_hdr *ext_hdr; void *ext_data; int ret = 0;
ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!ext_data) return -ENOMEM;
/* get first header */
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data, sizeof(*ext_hdr));
ext_hdr = ext_data;
dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
ext_hdr->type, ext_hdr->hdr.size);
/* process structure data */ switch (ext_hdr->type) { case SOF_IPC_EXT_WINDOW:
ret = sof_ipc3_get_ext_windows(sdev, ext_hdr); break; case SOF_IPC_EXT_CC_INFO:
ret = sof_ipc3_get_cc_info(sdev, ext_hdr); break; case SOF_IPC_EXT_UNUSED: case SOF_IPC_EXT_PROBE_INFO: case SOF_IPC_EXT_USER_ABI_INFO: /* They are supported but we don't do anything here */ break; default:
dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
ext_hdr->type, ext_hdr->hdr.size);
ret = 0; break;
}
if (ret < 0) {
dev_err(sdev->dev, "Failed to parse ext data type %d\n",
ext_hdr->type); break;
}
/* move to next header */
offset += ext_hdr->hdr.size;
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data, sizeof(*ext_hdr));
ext_hdr = ext_data;
}
dev_info(sdev->dev, "Firmware info: version %d:%d:%d-%s\n", v->major, v->minor,
v->micro, v->tag);
dev_info(sdev->dev, "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
SOF_ABI_VERSION_MAJOR(v->abi_version),
SOF_ABI_VERSION_MINOR(v->abi_version),
SOF_ABI_VERSION_PATCH(v->abi_version),
SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
dev_err(sdev->dev, "incompatible FW ABI version\n"); return -EINVAL;
}
if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
dev_err(sdev->dev, "FW ABI is more recent than kernel\n"); return -EINVAL;
}
/* copy the fw_version into debugfs at first boot */
memcpy(&sdev->fw_version, v, sizeof(*v));
return 0;
}
staticint ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
{ struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; int offset; int ret;
/* mailbox must be on 4k boundary */
offset = snd_sof_dsp_get_mailbox_offset(sdev); if (offset < 0) {
dev_err(sdev->dev, "%s: no mailbox offset\n", __func__); return offset;
}
dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
/* no need to re-check version/ABI for subsequent boots */ if (!sdev->first_boot) return 0;
/* * copy data from the DSP FW ready offset * Subsequent error handling is not needed for BLK_TYPE_SRAM
*/
ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready, sizeof(*fw_ready)); if (ret) {
dev_err(sdev->dev, "Unable to read fw_ready, read from TYPE_SRAM failed\n"); return ret;
}
/* make sure ABI version is compatible */
ret = sof_ipc3_validate_fw_version(sdev); if (ret < 0) return ret;
/* now check for extended data */
ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
if (hdr->size < sizeof(*hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
dev_err(sdev->dev, "The received message size is invalid: %u\n",
hdr->size); return;
}
cmd = hdr->cmd & SOF_GLB_TYPE_MASK;
/* check message type */ switch (cmd) { case SOF_IPC_GLB_REPLY:
dev_err(sdev->dev, "ipc reply unknown\n"); break; case SOF_IPC_FW_READY: /* check for FW boot completion */ if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
err = ipc3_fw_ready(sdev, cmd); if (err < 0)
sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); else
sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK);
/* wake up firmware loader */
wake_up(&sdev->boot_wait);
} break; case SOF_IPC_GLB_COMPOUND: case SOF_IPC_GLB_TPLG_MSG: case SOF_IPC_GLB_PM_MSG: break; case SOF_IPC_GLB_COMP_MSG:
rx_callback = ipc3_comp_notification; break; case SOF_IPC_GLB_STREAM_MSG:
rx_callback = ipc3_stream_message; break; case SOF_IPC_GLB_TRACE_MSG:
rx_callback = ipc3_trace_message; break; default:
dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd); break;
}
/* Call local handler for the message */ if (rx_callback)
rx_callback(sdev, msg_buf);
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.