debug.c (cac0b0887e5304bddfda91a4a7106f9328c31318) debug.c (3dc0d709177828a22dfc9d0072e3ac937ef90d06)
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 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>

--- 5 unchanged lines hidden (view full) ---

14#include <linux/debugfs.h>
15#include <linux/io.h>
16#include <linux/pm_runtime.h>
17#include <sound/sof/ext_manifest.h>
18#include <sound/sof/debug.h>
19#include "sof-priv.h"
20#include "ops.h"
21
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 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>

--- 5 unchanged lines hidden (view full) ---

14#include <linux/debugfs.h>
15#include <linux/io.h>
16#include <linux/pm_runtime.h>
17#include <sound/sof/ext_manifest.h>
18#include <sound/sof/debug.h>
19#include "sof-priv.h"
20#include "ops.h"
21
22#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
23#include "sof-probes.h"
24
25/**
26 * strsplit_u32 - Split string into sequence of u32 tokens
27 * @buf: String to split into tokens.
28 * @delim: String containing delimiter characters.
29 * @tkns: Returned u32 sequence pointer.
30 * @num_tkns: Returned number of tokens obtained.
31 */
32static int
33strsplit_u32(char **buf, const char *delim, u32 **tkns, size_t *num_tkns)
34{
35 char *s;
36 u32 *data, *tmp;
37 size_t count = 0;
38 size_t cap = 32;
39 int ret = 0;
40
41 *tkns = NULL;
42 *num_tkns = 0;
43 data = kcalloc(cap, sizeof(*data), GFP_KERNEL);
44 if (!data)
45 return -ENOMEM;
46
47 while ((s = strsep(buf, delim)) != NULL) {
48 ret = kstrtouint(s, 0, data + count);
49 if (ret)
50 goto exit;
51 if (++count >= cap) {
52 cap *= 2;
53 tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL);
54 if (!tmp) {
55 ret = -ENOMEM;
56 goto exit;
57 }
58 data = tmp;
59 }
60 }
61
62 if (!count)
63 goto exit;
64 *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL);
65 if (*tkns == NULL) {
66 ret = -ENOMEM;
67 goto exit;
68 }
69 *num_tkns = count;
70
71exit:
72 kfree(data);
73 return ret;
74}
75
76static int tokenize_input(const char __user *from, size_t count,
77 loff_t *ppos, u32 **tkns, size_t *num_tkns)
78{
79 char *buf;
80 int ret;
81
82 buf = kmalloc(count + 1, GFP_KERNEL);
83 if (!buf)
84 return -ENOMEM;
85
86 ret = simple_write_to_buffer(buf, count, ppos, from, count);
87 if (ret != count) {
88 ret = ret >= 0 ? -EIO : ret;
89 goto exit;
90 }
91
92 buf[count] = '\0';
93 ret = strsplit_u32((char **)&buf, ",", tkns, num_tkns);
94exit:
95 kfree(buf);
96 return ret;
97}
98
99static ssize_t probe_points_read(struct file *file,
100 char __user *to, size_t count, loff_t *ppos)
101{
102 struct snd_sof_dfsentry *dfse = file->private_data;
103 struct snd_sof_dev *sdev = dfse->sdev;
104 struct sof_probe_point_desc *desc;
105 size_t num_desc, len = 0;
106 char *buf;
107 int i, ret;
108
109 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
110 dev_warn(sdev->dev, "no extractor stream running\n");
111 return -ENOENT;
112 }
113
114 buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
115 if (!buf)
116 return -ENOMEM;
117
118 ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc);
119 if (ret < 0)
120 goto exit;
121
122 for (i = 0; i < num_desc; i++) {
123 ret = snprintf(buf + len, PAGE_SIZE - len,
124 "Id: %#010x Purpose: %d Node id: %#x\n",
125 desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
126 if (ret < 0)
127 goto free_desc;
128 len += ret;
129 }
130
131 ret = simple_read_from_buffer(to, count, ppos, buf, len);
132free_desc:
133 kfree(desc);
134exit:
135 kfree(buf);
136 return ret;
137}
138
139static ssize_t probe_points_write(struct file *file,
140 const char __user *from, size_t count, loff_t *ppos)
141{
142 struct snd_sof_dfsentry *dfse = file->private_data;
143 struct snd_sof_dev *sdev = dfse->sdev;
144 struct sof_probe_point_desc *desc;
145 size_t num_tkns, bytes;
146 u32 *tkns;
147 int ret;
148
149 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
150 dev_warn(sdev->dev, "no extractor stream running\n");
151 return -ENOENT;
152 }
153
154 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
155 if (ret < 0)
156 return ret;
157 bytes = sizeof(*tkns) * num_tkns;
158 if (!num_tkns || (bytes % sizeof(*desc))) {
159 ret = -EINVAL;
160 goto exit;
161 }
162
163 desc = (struct sof_probe_point_desc *)tkns;
164 ret = sof_ipc_probe_points_add(sdev,
165 desc, bytes / sizeof(*desc));
166 if (!ret)
167 ret = count;
168exit:
169 kfree(tkns);
170 return ret;
171}
172
173static const struct file_operations probe_points_fops = {
174 .open = simple_open,
175 .read = probe_points_read,
176 .write = probe_points_write,
177 .llseek = default_llseek,
178};
179
180static ssize_t probe_points_remove_write(struct file *file,
181 const char __user *from, size_t count, loff_t *ppos)
182{
183 struct snd_sof_dfsentry *dfse = file->private_data;
184 struct snd_sof_dev *sdev = dfse->sdev;
185 size_t num_tkns;
186 u32 *tkns;
187 int ret;
188
189 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
190 dev_warn(sdev->dev, "no extractor stream running\n");
191 return -ENOENT;
192 }
193
194 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
195 if (ret < 0)
196 return ret;
197 if (!num_tkns) {
198 ret = -EINVAL;
199 goto exit;
200 }
201
202 ret = sof_ipc_probe_points_remove(sdev, tkns, num_tkns);
203 if (!ret)
204 ret = count;
205exit:
206 kfree(tkns);
207 return ret;
208}
209
210static const struct file_operations probe_points_remove_fops = {
211 .open = simple_open,
212 .write = probe_points_remove_write,
213 .llseek = default_llseek,
214};
215
216static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev,
217 const char *name, mode_t mode,
218 const struct file_operations *fops)
219{
220 struct snd_sof_dfsentry *dfse;
221
222 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
223 if (!dfse)
224 return -ENOMEM;
225
226 dfse->type = SOF_DFSENTRY_TYPE_BUF;
227 dfse->sdev = sdev;
228
229 debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
230 /* add to dfsentry list */
231 list_add(&dfse->list, &sdev->dfsentry_list);
232
233 return 0;
234}
235#endif
236
237static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
238 size_t count, loff_t *ppos)
239{
240 size_t size;
241 char *string;
242 int ret;
243
244 string = kzalloc(count+1, GFP_KERNEL);

--- 319 unchanged lines hidden (view full) ---

564 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] +
565 map->offset, map->size,
566 map->name, map->access_type);
567 /* errors are only due to memory allocation, not debugfs */
568 if (err < 0)
569 return err;
570 }
571
22static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
23 size_t count, loff_t *ppos)
24{
25 size_t size;
26 char *string;
27 int ret;
28
29 string = kzalloc(count+1, GFP_KERNEL);

--- 319 unchanged lines hidden (view full) ---

349 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] +
350 map->offset, map->size,
351 map->name, map->access_type);
352 /* errors are only due to memory allocation, not debugfs */
353 if (err < 0)
354 return err;
355 }
356
572#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
573 err = snd_sof_debugfs_probe_item(sdev, "probe_points",
574 0644, &probe_points_fops);
575 if (err < 0)
576 return err;
577 err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove",
578 0200, &probe_points_remove_fops);
579 if (err < 0)
580 return err;
581#endif
582
583 return 0;
584}
585EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
586
587void snd_sof_free_debug(struct snd_sof_dev *sdev)
588{
589 debugfs_remove_recursive(sdev->debugfs_root);
590}

--- 85 unchanged lines hidden ---
357 return 0;
358}
359EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
360
361void snd_sof_free_debug(struct snd_sof_dev *sdev)
362{
363 debugfs_remove_recursive(sdev->debugfs_root);
364}

--- 85 unchanged lines hidden ---