Linux 6.7-rc7
[linux-modified.git] / sound / soc / sof / ipc4-telemetry.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018-2023 Intel Corporation. All rights reserved.
7 //
8
9 #include <linux/debugfs.h>
10 #include <linux/io.h>
11 #include <linux/pm_runtime.h>
12 #include <sound/sof/debug.h>
13 #include <sound/sof/ipc4/header.h>
14 #include "sof-priv.h"
15 #include "ops.h"
16 #include "ipc4-telemetry.h"
17 #include "ipc4-priv.h"
18
19 static void __iomem *sof_ipc4_query_exception_address(struct snd_sof_dev *sdev)
20 {
21         u32 type = SOF_IPC4_DEBUG_SLOT_TELEMETRY;
22         size_t telemetry_slot_offset;
23         u32 offset;
24
25         telemetry_slot_offset = sof_ipc4_find_debug_slot_offset_by_type(sdev, type);
26         if (!telemetry_slot_offset)
27                 return NULL;
28
29         /* skip the first separator magic number */
30         offset = telemetry_slot_offset + sizeof(u32);
31
32         return sdev->bar[sdev->mailbox_bar] + offset;
33 }
34
35 static ssize_t sof_telemetry_entry_read(struct file *file, char __user *buffer,
36                                         size_t count, loff_t *ppos)
37 {
38         struct snd_sof_dfsentry *dfse = file->private_data;
39         struct snd_sof_dev *sdev = dfse->sdev;
40         void __iomem *io_addr;
41         loff_t pos = *ppos;
42         size_t size_ret;
43         u8 *buf;
44
45         if (pos < 0)
46                 return -EINVAL;
47         /* skip the first separator magic number */
48         if (pos >= SOF_IPC4_DEBUG_SLOT_SIZE - 4 || !count)
49                 return 0;
50         if (count > SOF_IPC4_DEBUG_SLOT_SIZE - 4 - pos)
51                 count = SOF_IPC4_DEBUG_SLOT_SIZE - 4 - pos;
52
53         io_addr = sof_ipc4_query_exception_address(sdev);
54         if (!io_addr)
55                 return -EFAULT;
56
57         buf = kzalloc(SOF_IPC4_DEBUG_SLOT_SIZE - 4, GFP_KERNEL);
58         if (!buf)
59                 return -ENOMEM;
60
61         memcpy_fromio(buf, io_addr, SOF_IPC4_DEBUG_SLOT_SIZE - 4);
62         size_ret = copy_to_user(buffer, buf + pos, count);
63         if (size_ret) {
64                 kfree(buf);
65                 return -EFAULT;
66         }
67
68         *ppos = pos + count;
69         kfree(buf);
70
71         return count;
72 }
73
74 static const struct file_operations sof_telemetry_fops = {
75         .open = simple_open,
76         .read = sof_telemetry_entry_read,
77 };
78
79 void sof_ipc4_create_exception_debugfs_node(struct snd_sof_dev *sdev)
80 {
81         struct snd_sof_dfsentry *dfse;
82
83         dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
84         if (!dfse)
85                 return;
86
87         dfse->type = SOF_DFSENTRY_TYPE_IOMEM;
88         dfse->size = SOF_IPC4_DEBUG_SLOT_SIZE - 4;
89         dfse->access_type = SOF_DEBUGFS_ACCESS_ALWAYS;
90         dfse->sdev = sdev;
91
92         list_add(&dfse->list, &sdev->dfsentry_list);
93
94         debugfs_create_file("exception", 0444, sdev->debugfs_root, dfse, &sof_telemetry_fops);
95 }