// 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) 2018 Intel Corporation // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // // Generic debug routines used to export DSP MMIO and memories to userspace // for firmware debugging. //
/* validate position & count */ if (pos < 0) return -EINVAL; if (pos >= size || !count) return 0; /* find the minimum. min() is not used since it adds sparse warnings */ if (count > size - pos)
count = size - pos;
/* intermediate buffer size must be u32 multiple */
size = ALIGN(count, 4);
/* if start position is unaligned, read extra u32 */ if (unlikely(pos != *ppos)) {
skip = *ppos - pos; if (pos + size + 4 < dfse->size)
size += 4;
}
buf = kzalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM;
if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* * If the DSP is active: copy from IO. * If the DSP is suspended: * - Copy from IO if the memory is always accessible. * - Otherwise, copy from cached buffer.
*/ if (pm_runtime_active(sdev->dev) ||
dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) {
memcpy_fromio(buf, dfse->io_mem + pos, size);
} else {
dev_info(sdev->dev, "Copying cached debugfs data\n");
memcpy(buf, dfse->cache_buf + pos, size);
} #else /* if the DSP is in D3 */ if (!pm_runtime_active(sdev->dev) &&
dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
dev_err(sdev->dev, "error: debugfs entry cannot be read in DSP D3\n");
kfree(buf); return -EINVAL;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* * allocate cache buffer that will be used to save the mem window * contents prior to suspend
*/ if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL); if (!dfse->cache_buf) return -ENOMEM;
} #endif
reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); if (!reply) return -ENOMEM;
ret = pm_runtime_resume_and_get(sdev->dev); if (ret < 0 && ret != -EACCES) {
dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); goto error;
}
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
pm_runtime_put_autosuspend(sdev->dev); if (ret < 0 || reply->rhdr.error < 0) {
ret = min(ret, reply->rhdr.error);
dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret); goto error;
}
if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
reply->rhdr.hdr.size);
ret = -EINVAL; goto error;
}
for (i = 0, len = 0; i < reply->num_elems; i++) {
ret = scnprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
reply->elems[i].zone, reply->elems[i].id,
reply->elems[i].used, reply->elems[i].free); if (ret < 0) goto error;
len += ret;
}
/* read memory info from FW only once for each file read */ if (!*ppos) {
dfse->buf_data_size = 0;
data_length = memory_info_update(sdev, dfse->buf, dfse->size); if (data_length < 0) return data_length;
dfse->buf_data_size = data_length;
}
/* allocate buffer memory only in first open run, to save memory when unused */ if (!dfse->buf) {
dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); if (!dfse->buf) return -ENOMEM;
dfse->size = PAGE_SIZE;
}
/* add to dfsentry list */
list_add(&dfse->list, &sdev->dfsentry_list); return 0;
}
EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
{ conststruct snd_sof_dsp_ops *ops = sof_ops(sdev); struct snd_sof_pdata *plat_data = sdev->pdata; conststruct snd_sof_debugfs_map *map; struct dentry *fw_profile; int i; int err;
/* use "sof" as top level debugFS dir */
sdev->debugfs_root = debugfs_create_dir("sof", NULL);
/* expose firmware/topology prefix/names for test purposes */
fw_profile = debugfs_create_dir("fw_profile", sdev->debugfs_root);
debugfs_create_str("fw_path", 0444, fw_profile,
(char **)&plat_data->fw_filename_prefix); /* library path is not valid for IPC3 */ if (plat_data->ipc_type != SOF_IPC_TYPE_3) { /* * fw_lib_prefix can be NULL if the vendor/platform does not * support loadable libraries
*/ if (plat_data->fw_lib_prefix) {
debugfs_create_str("fw_lib_path", 0444, fw_profile,
(char **)&plat_data->fw_lib_prefix);
} else { staticchar *fw_lib_path;
fw_lib_path = devm_kasprintf(sdev->dev, GFP_KERNEL, "Not supported"); if (!fw_lib_path) return -ENOMEM;
/* init dfsentry list */
INIT_LIST_HEAD(&sdev->dfsentry_list);
/* create debugFS files for platform specific MMIO/DSP memories */ for (i = 0; i < ops->debug_map_count; i++) {
map = &ops->debug_map[i];
err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] +
map->offset, map->size,
map->name, map->access_type); /* errors are only due to memory allocation, not debugfs */ if (err < 0) return err;
}
staticvoid snd_sof_ipc_dump(struct snd_sof_dev *sdev)
{ if (sof_ops(sdev)->ipc_dump && !sdev->ipc_dump_printed) {
dev_err(sdev->dev, "------------[ IPC dump start ]------------\n");
sof_ops(sdev)->ipc_dump(sdev);
dev_err(sdev->dev, "------------[ IPC dump end ]------------\n"); if (!sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS))
sdev->ipc_dump_printed = true;
}
}
void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, constchar *msg)
{ if ((IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) && !sdev->d3_prevented) { /* should we prevent DSP entering D3 ? */ if (!sdev->ipc_dump_printed)
dev_info(sdev->dev, "Attempting to prevent DSP from entering D3 state to preserve context\n");
if (pm_runtime_get_if_in_use(sdev->dev) == 1)
sdev->d3_prevented = true;
}
/* dump vital information to the logs */
snd_sof_ipc_dump(sdev);
snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
sof_fw_trace_fw_crashed(sdev);
}
EXPORT_SYMBOL(snd_sof_handle_fw_exception);
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
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.