0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/debugfs.h>
0015 #include <linux/io.h>
0016 #include <linux/pm_runtime.h>
0017 #include <sound/sof/ext_manifest.h>
0018 #include <sound/sof/debug.h>
0019 #include "sof-priv.h"
0020 #include "ops.h"
0021
0022 static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
0023 size_t count, loff_t *ppos)
0024 {
0025 size_t size;
0026 char *string;
0027 int ret;
0028
0029 string = kzalloc(count+1, GFP_KERNEL);
0030 if (!string)
0031 return -ENOMEM;
0032
0033 size = simple_write_to_buffer(string, count, ppos, buffer, count);
0034 ret = size;
0035
0036 kfree(string);
0037 return ret;
0038 }
0039
0040 static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer,
0041 size_t count, loff_t *ppos)
0042 {
0043 struct snd_sof_dfsentry *dfse = file->private_data;
0044 struct snd_sof_dev *sdev = dfse->sdev;
0045 loff_t pos = *ppos;
0046 size_t size_ret;
0047 int skip = 0;
0048 int size;
0049 u8 *buf;
0050
0051 size = dfse->size;
0052
0053
0054 if (pos < 0)
0055 return -EINVAL;
0056 if (pos >= size || !count)
0057 return 0;
0058
0059 if (count > size - pos)
0060 count = size - pos;
0061
0062
0063 pos = ALIGN_DOWN(pos, 4);
0064
0065
0066 size = ALIGN(count, 4);
0067
0068
0069 if (unlikely(pos != *ppos)) {
0070 skip = *ppos - pos;
0071 if (pos + size + 4 < dfse->size)
0072 size += 4;
0073 }
0074
0075 buf = kzalloc(size, GFP_KERNEL);
0076 if (!buf)
0077 return -ENOMEM;
0078
0079 if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) {
0080 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
0081
0082
0083
0084
0085
0086
0087 if (pm_runtime_active(sdev->dev) ||
0088 dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) {
0089 memcpy_fromio(buf, dfse->io_mem + pos, size);
0090 } else {
0091 dev_info(sdev->dev,
0092 "Copying cached debugfs data\n");
0093 memcpy(buf, dfse->cache_buf + pos, size);
0094 }
0095 #else
0096
0097 if (!pm_runtime_active(sdev->dev) &&
0098 dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
0099 dev_err(sdev->dev,
0100 "error: debugfs entry cannot be read in DSP D3\n");
0101 kfree(buf);
0102 return -EINVAL;
0103 }
0104
0105 memcpy_fromio(buf, dfse->io_mem + pos, size);
0106 #endif
0107 } else {
0108 memcpy(buf, ((u8 *)(dfse->buf) + pos), size);
0109 }
0110
0111
0112 size_ret = copy_to_user(buffer, buf + skip, count);
0113
0114 kfree(buf);
0115
0116
0117 if (size_ret)
0118 return -EFAULT;
0119
0120 *ppos = pos + count;
0121
0122 return count;
0123 }
0124
0125 static const struct file_operations sof_dfs_fops = {
0126 .open = simple_open,
0127 .read = sof_dfsentry_read,
0128 .llseek = default_llseek,
0129 .write = sof_dfsentry_write,
0130 };
0131
0132
0133 static int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev,
0134 void __iomem *base, size_t size,
0135 const char *name,
0136 enum sof_debugfs_access_type access_type)
0137 {
0138 struct snd_sof_dfsentry *dfse;
0139
0140 if (!sdev)
0141 return -EINVAL;
0142
0143 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
0144 if (!dfse)
0145 return -ENOMEM;
0146
0147 dfse->type = SOF_DFSENTRY_TYPE_IOMEM;
0148 dfse->io_mem = base;
0149 dfse->size = size;
0150 dfse->sdev = sdev;
0151 dfse->access_type = access_type;
0152
0153 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
0154
0155
0156
0157
0158 if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
0159 dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL);
0160 if (!dfse->cache_buf)
0161 return -ENOMEM;
0162 }
0163 #endif
0164
0165 debugfs_create_file(name, 0444, sdev->debugfs_root, dfse,
0166 &sof_dfs_fops);
0167
0168
0169 list_add(&dfse->list, &sdev->dfsentry_list);
0170
0171 return 0;
0172 }
0173
0174 int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev,
0175 enum snd_sof_fw_blk_type blk_type, u32 offset,
0176 size_t size, const char *name,
0177 enum sof_debugfs_access_type access_type)
0178 {
0179 int bar = snd_sof_dsp_get_bar_index(sdev, blk_type);
0180
0181 if (bar < 0)
0182 return bar;
0183
0184 return snd_sof_debugfs_io_item(sdev, sdev->bar[bar] + offset, size, name,
0185 access_type);
0186 }
0187 EXPORT_SYMBOL_GPL(snd_sof_debugfs_add_region_item_iomem);
0188
0189
0190 int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
0191 void *base, size_t size,
0192 const char *name, mode_t mode)
0193 {
0194 struct snd_sof_dfsentry *dfse;
0195
0196 if (!sdev)
0197 return -EINVAL;
0198
0199 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
0200 if (!dfse)
0201 return -ENOMEM;
0202
0203 dfse->type = SOF_DFSENTRY_TYPE_BUF;
0204 dfse->buf = base;
0205 dfse->size = size;
0206 dfse->sdev = sdev;
0207
0208 debugfs_create_file(name, mode, sdev->debugfs_root, dfse,
0209 &sof_dfs_fops);
0210
0211 list_add(&dfse->list, &sdev->dfsentry_list);
0212
0213 return 0;
0214 }
0215 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
0216
0217 static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size)
0218 {
0219 struct sof_ipc_cmd_hdr msg = {
0220 .size = sizeof(struct sof_ipc_cmd_hdr),
0221 .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE,
0222 };
0223 struct sof_ipc_dbg_mem_usage *reply;
0224 int len;
0225 int ret;
0226 int i;
0227
0228 reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
0229 if (!reply)
0230 return -ENOMEM;
0231
0232 ret = pm_runtime_resume_and_get(sdev->dev);
0233 if (ret < 0 && ret != -EACCES) {
0234 dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
0235 goto error;
0236 }
0237
0238 ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
0239 pm_runtime_mark_last_busy(sdev->dev);
0240 pm_runtime_put_autosuspend(sdev->dev);
0241 if (ret < 0 || reply->rhdr.error < 0) {
0242 ret = min(ret, reply->rhdr.error);
0243 dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret);
0244 goto error;
0245 }
0246
0247 if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) {
0248 dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n",
0249 reply->rhdr.hdr.size);
0250 ret = -EINVAL;
0251 goto error;
0252 }
0253
0254 for (i = 0, len = 0; i < reply->num_elems; i++) {
0255 ret = scnprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
0256 reply->elems[i].zone, reply->elems[i].id,
0257 reply->elems[i].used, reply->elems[i].free);
0258 if (ret < 0)
0259 goto error;
0260 len += ret;
0261 }
0262
0263 ret = len;
0264 error:
0265 kfree(reply);
0266 return ret;
0267 }
0268
0269 static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
0270 {
0271 struct snd_sof_dfsentry *dfse = file->private_data;
0272 struct snd_sof_dev *sdev = dfse->sdev;
0273 int data_length;
0274
0275
0276 if (!*ppos) {
0277 dfse->buf_data_size = 0;
0278 data_length = memory_info_update(sdev, dfse->buf, dfse->size);
0279 if (data_length < 0)
0280 return data_length;
0281 dfse->buf_data_size = data_length;
0282 }
0283
0284 return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size);
0285 }
0286
0287 static int memory_info_open(struct inode *inode, struct file *file)
0288 {
0289 struct snd_sof_dfsentry *dfse = inode->i_private;
0290 struct snd_sof_dev *sdev = dfse->sdev;
0291
0292 file->private_data = dfse;
0293
0294
0295 if (!dfse->buf) {
0296 dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL);
0297 if (!dfse->buf)
0298 return -ENOMEM;
0299 dfse->size = PAGE_SIZE;
0300 }
0301
0302 return 0;
0303 }
0304
0305 static const struct file_operations memory_info_fops = {
0306 .open = memory_info_open,
0307 .read = memory_info_read,
0308 .llseek = default_llseek,
0309 };
0310
0311 int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev)
0312 {
0313 struct snd_sof_dfsentry *dfse;
0314
0315 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
0316 if (!dfse)
0317 return -ENOMEM;
0318
0319
0320 dfse->type = SOF_DFSENTRY_TYPE_BUF;
0321 dfse->sdev = sdev;
0322
0323 debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops);
0324
0325
0326 list_add(&dfse->list, &sdev->dfsentry_list);
0327 return 0;
0328 }
0329 EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
0330
0331 int snd_sof_dbg_init(struct snd_sof_dev *sdev)
0332 {
0333 struct snd_sof_dsp_ops *ops = sof_ops(sdev);
0334 const struct snd_sof_debugfs_map *map;
0335 int i;
0336 int err;
0337
0338
0339 sdev->debugfs_root = debugfs_create_dir("sof", NULL);
0340
0341
0342 INIT_LIST_HEAD(&sdev->dfsentry_list);
0343
0344
0345 for (i = 0; i < ops->debug_map_count; i++) {
0346 map = &ops->debug_map[i];
0347
0348 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] +
0349 map->offset, map->size,
0350 map->name, map->access_type);
0351
0352 if (err < 0)
0353 return err;
0354 }
0355
0356 return 0;
0357 }
0358 EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
0359
0360 void snd_sof_free_debug(struct snd_sof_dev *sdev)
0361 {
0362 debugfs_remove_recursive(sdev->debugfs_root);
0363 }
0364 EXPORT_SYMBOL_GPL(snd_sof_free_debug);
0365
0366 static const struct soc_fw_state_info {
0367 enum sof_fw_state state;
0368 const char *name;
0369 } fw_state_dbg[] = {
0370 {SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"},
0371 {SOF_FW_BOOT_PREPARE, "SOF_FW_BOOT_PREPARE"},
0372 {SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"},
0373 {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"},
0374 {SOF_FW_BOOT_READY_FAILED, "SOF_FW_BOOT_READY_FAILED"},
0375 {SOF_FW_BOOT_READY_OK, "SOF_FW_BOOT_READY_OK"},
0376 {SOF_FW_BOOT_COMPLETE, "SOF_FW_BOOT_COMPLETE"},
0377 {SOF_FW_CRASHED, "SOF_FW_CRASHED"},
0378 };
0379
0380 static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev, const char *level)
0381 {
0382 int i;
0383
0384 for (i = 0; i < ARRAY_SIZE(fw_state_dbg); i++) {
0385 if (sdev->fw_state == fw_state_dbg[i].state) {
0386 dev_printk(level, sdev->dev, "fw_state: %s (%d)\n",
0387 fw_state_dbg[i].name, i);
0388 return;
0389 }
0390 }
0391
0392 dev_printk(level, sdev->dev, "fw_state: UNKNOWN (%d)\n", sdev->fw_state);
0393 }
0394
0395 void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, const char *msg, u32 flags)
0396 {
0397 char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
0398 bool print_all = sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS);
0399
0400 if (flags & SOF_DBG_DUMP_OPTIONAL && !print_all)
0401 return;
0402
0403 if (sof_ops(sdev)->dbg_dump && !sdev->dbg_dump_printed) {
0404 dev_printk(level, sdev->dev,
0405 "------------[ DSP dump start ]------------\n");
0406 if (msg)
0407 dev_printk(level, sdev->dev, "%s\n", msg);
0408 snd_sof_dbg_print_fw_state(sdev, level);
0409 sof_ops(sdev)->dbg_dump(sdev, flags);
0410 dev_printk(level, sdev->dev,
0411 "------------[ DSP dump end ]------------\n");
0412 if (!print_all)
0413 sdev->dbg_dump_printed = true;
0414 } else if (msg) {
0415 dev_printk(level, sdev->dev, "%s\n", msg);
0416 }
0417 }
0418 EXPORT_SYMBOL(snd_sof_dsp_dbg_dump);
0419
0420 static void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
0421 {
0422 if (sof_ops(sdev)->ipc_dump && !sdev->ipc_dump_printed) {
0423 dev_err(sdev->dev, "------------[ IPC dump start ]------------\n");
0424 sof_ops(sdev)->ipc_dump(sdev);
0425 dev_err(sdev->dev, "------------[ IPC dump end ]------------\n");
0426 if (!sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS))
0427 sdev->ipc_dump_printed = true;
0428 }
0429 }
0430
0431 void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg)
0432 {
0433 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
0434 sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) {
0435
0436 if (!sdev->ipc_dump_printed)
0437 dev_info(sdev->dev,
0438 "preventing DSP entering D3 state to preserve context\n");
0439 pm_runtime_get_noresume(sdev->dev);
0440 }
0441
0442
0443 snd_sof_ipc_dump(sdev);
0444 snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
0445 sof_fw_trace_fw_crashed(sdev);
0446 }
0447 EXPORT_SYMBOL(snd_sof_handle_fw_exception);