On Tue, Jan 28, 2020 at 2:51 AM Cezary Rojewski <cezary.rojewski@xxxxxxxxx> wrote: > Define debugfs subdirectory delegated for IPC communication with DSP. > Input format: uint,uint,(...) which are later translated into DWORDS > sequence and further into instances of struct of interest given the IPC > type. > > For Extractor probes, following have been enabled: > - PROBE_POINT_ADD (echo <..> probe_points) > - PROBE_POINT_REMOVE (echo <..> probe_points_remove) > - PROBE_POINT_INFO (cat probe_points) > > Signed-off-by: Cezary Rojewski <cezary.rojewski@xxxxxxxxx> > --- > > Changes in v2: > - renamed debugfs probe functions as requested by Pierre > > > sound/soc/sof/debug.c | 208 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 208 insertions(+) > > diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c > index d2b3b99d3a20..d38ab59e9a98 100644 > --- a/sound/soc/sof/debug.c > +++ b/sound/soc/sof/debug.c > @@ -17,6 +17,203 @@ > #include "sof-priv.h" > #include "ops.h" > > +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) > +#include "probe.h" > + > +/** > + * strsplit_u32 - Split string into sequence of u32 tokens > + * @buf: String to split into tokens. > + * @delim: String containing delimiter characters. > + * @tkns: Returned u32 sequence pointer. > + * @num_tkns: Returned number of tokens obtained. > + */ > +static int > +strsplit_u32(char **buf, const char *delim, u32 **tkns, size_t *num_tkns) > +{ > + char *s; > + u32 *data, *tmp; > + size_t count = 0; > + size_t cap = 32; > + int ret = 0; > + > + *tkns = NULL; > + *num_tkns = 0; > + data = kcalloc(cap, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + while ((s = strsep(buf, delim)) != NULL) { > + ret = kstrtouint(s, 0, data + count); > + if (ret) > + goto exit; > + if (++count >= cap) { > + cap *= 2; > + tmp = krealloc(data, cap * sizeof(*data), > GFP_KERNEL); > + if (!tmp) { > + ret = -ENOMEM; > + goto exit; > + } > + data = tmp; > + } > + } > + > + if (!count) > + goto exit; > + *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL); > + if (*tkns == NULL) { > + ret = -ENOMEM; > + goto exit; > + } > + *num_tkns = count; > + > +exit: > + kfree(data); > + return ret; > +} > + > +static int tokenize_input(const char __user *from, size_t count, > + loff_t *ppos, u32 **tkns, size_t *num_tkns) > +{ > + char *buf; > + int ret; > + > + buf = kmalloc(count + 1, GFP_KERNEL); > + if (!buf) > + return -ENOMEM; > + > + ret = simple_write_to_buffer(buf, count, ppos, from, count); > + if (ret != count) { > + ret = ret >= 0 ? -EIO : ret; > + goto exit; > + } > + > + buf[count] = '\0'; > + ret = strsplit_u32((char **)&buf, ",", tkns, num_tkns); > +exit: > + kfree(buf); > + return ret; > +} > + > +static ssize_t probe_points_read(struct file *file, > + char __user *to, size_t count, loff_t *ppos) > +{ > + struct snd_sof_dfsentry *dfse = file->private_data; > + struct sof_probe_point_desc *desc; > + size_t num_desc, len = 0; > + char *buf; > + int i, ret; > + > + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); > + if (!buf) > + return -ENOMEM; > + > + ret = sof_ipc_probe_points_info(dfse->sdev, &desc, &num_desc); > + if (ret < 0) > + goto exit; > + > + for (i = 0; i < num_desc; i++) { > + ret = snprintf(buf + len, PAGE_SIZE - len, > + "Id: %#010x Purpose: %d Node id: %#x\n", > + desc[i].buffer_id, desc[i].purpose, > desc[i].stream_tag); > + if (ret < 0) > + goto free_desc; > + len += ret; > + } > + > + ret = simple_read_from_buffer(to, count, ppos, buf, len); > +free_desc: > + kfree(desc); > +exit: > + kfree(buf); > + return ret; > +} > + > +static ssize_t probe_points_write(struct file *file, > + const char __user *from, size_t count, loff_t *ppos) > +{ > + struct snd_sof_dfsentry *dfse = file->private_data; > + struct sof_probe_point_desc *desc; > + size_t num_tkns, bytes; > + u32 *tkns; > + int ret; > + > + ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); > + if (ret < 0) > + return ret; > + bytes = sizeof(*tkns) * num_tkns; > + if (!num_tkns || (bytes % sizeof(*desc))) { > + ret = -EINVAL; > + goto exit; > + } > + > + desc = (struct sof_probe_point_desc *)tkns; > + ret = sof_ipc_probe_points_add(dfse->sdev, > + desc, bytes / sizeof(*desc)); > + if (!ret) > + ret = count; > +exit: > + kfree(tkns); > + return ret; > +} > + > +static const struct file_operations probe_points_fops = { > + .open = simple_open, > + .read = probe_points_read, > + .write = probe_points_write, > + .llseek = default_llseek, > +}; > + > +static ssize_t probe_points_remove_write(struct file *file, > + const char __user *from, size_t count, loff_t *ppos) > +{ > + struct snd_sof_dfsentry *dfse = file->private_data; > + size_t num_tkns; > + u32 *tkns; > + int ret; > + > + ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); > + if (ret < 0) > + return ret; > + if (!num_tkns) { > + ret = -EINVAL; > + goto exit; > + } > + > + ret = sof_ipc_probe_points_remove(dfse->sdev, tkns, num_tkns); > + if (!ret) > + ret = count; > +exit: > + kfree(tkns); > + return ret; > +} > + > +static const struct file_operations probe_points_remove_fops = { > + .open = simple_open, > + .write = probe_points_remove_write, > + .llseek = default_llseek, > +}; > + > +static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev, > + const char *name, mode_t mode, > + const struct file_operations *fops) Hi Cezary, Any particular reason to not use the existing snd_sof_debugfs_buf_item() and adding a new one that does pretty much the same thing? Thanks, Ranjani _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx https://mailman.alsa-project.org/mailman/listinfo/alsa-devel