summaryrefslogtreecommitdiff
path: root/sound/soc/sof/debug.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-04-02 15:50:04 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-04-02 15:50:04 -0700
commit848960e576dafc8ed54c691b2f70b92e1fdea9ba (patch)
tree27ea80003da03b81f0b188d3712f0194745126d9 /sound/soc/sof/debug.c
parentbc3b3f4bfbded031a11c4284106adddbfacd05bb (diff)
parent5c6cd7021a05a02fcf37f360592d7c18d4d807fb (diff)
Merge tag 'sound-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "This became again a busy development cycle. There are few ALSA core updates (merely API cleanups and sparse fixes), with the majority of other changes are found in ASoC scene. Here are some highlights: ALSA core: - More helper macros for sparse warning fixes (e.g. bitwise types) - Slight optimization of PCM OSS locks - Make common handling for PCM / compress buffers (for SOF) ASoC: - Lots of code refactoring and modernization for (still ongoing) componentization works - Conversion of SND_SOC_ALL_CODECS to use imply - Continued refactoring and fixing of the Intel SOF/SST support, including the initial (but still incomplete) SoundWire support - SoundWire and more advanced clocking support for Realtek RT5682 - Support for amlogic GX, Meson 8, Meson 8B and T9015 DAC, Broadcom DSL/PON, Ingenic JZ4760 and JZ4770, Realtek RL6231, and TI TAS2563 and TLV320ADCX140 HD-audio: - Optimizations in HDMI jack handling - A few new quirks and fixups for Realtek codecs USB-audio: - Delayed registration support - New quirks for Motu, Kingston, Presonus" * tag 'sound-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (415 commits) ALSA: usb-audio: Fix case when USB MIDI interface has more than one extra endpoint descriptor Revert "ALSA: uapi: Drop asound.h inclusion from asoc.h" ALSA: hda/realtek - Remove now-unnecessary XPS 13 headphone noise fixups ALSA: hda/realtek - Set principled PC Beep configuration for ALC256 ALSA: doc: Document PC Beep Hidden Register on Realtek ALC256 ALSA: hda/realtek - a fake key event is triggered by running shutup ALSA: hda: default enable CA0132 DSP support ASoC: amd: acp3x-pcm-dma: clean up two indentation issues ASoC: tlv320adcx140: Remove undocumented property ASoC: Intel: sof_sdw: Add Volteer support with RT5682 SNDW helper function ASoC: Intel: common: add match table for TGL RT5682 SoundWire driver ASoC: Intel: boards: add sof_sdw machine driver ASoC: Intel: soc-acpi: update topology and driver name for SoundWire platforms ASoC: rt5682: move DAI clock registry to I2S mode ASoC: pxa: magician: convert to use i2c_new_client_device() ASoC: SOF: Intel: hda-ctrl: add reset cycle before parsing capabilities Asoc: SOF: Intel: hda: check SoundWire wakeen interrupt in irq thread ASoC: SOF: Intel: hda: add WAKEEN interrupt support for SoundWire ASoC: SOF: Intel: hda: add parameter to control SoundWire clock stop quirks ASoC: SOF: Intel: hda: merge IPC, stream and SoundWire interrupt handlers ...
Diffstat (limited to 'sound/soc/sof/debug.c')
-rw-r--r--sound/soc/sof/debug.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index d2b3b99d3a20..b5c0d6cf72cc 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -17,6 +17,221 @@
#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 snd_sof_dev *sdev = dfse->sdev;
+ struct sof_probe_point_desc *desc;
+ size_t num_desc, len = 0;
+ char *buf;
+ int i, ret;
+
+ if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
+ dev_warn(sdev->dev, "no extractor stream running\n");
+ return -ENOENT;
+ }
+
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = sof_ipc_probe_points_info(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 snd_sof_dev *sdev = dfse->sdev;
+ struct sof_probe_point_desc *desc;
+ size_t num_tkns, bytes;
+ u32 *tkns;
+ int ret;
+
+ if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
+ dev_warn(sdev->dev, "no extractor stream running\n");
+ return -ENOENT;
+ }
+
+ 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(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;
+ struct snd_sof_dev *sdev = dfse->sdev;
+ size_t num_tkns;
+ u32 *tkns;
+ int ret;
+
+ if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) {
+ dev_warn(sdev->dev, "no extractor stream running\n");
+ return -ENOENT;
+ }
+
+ 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(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)
+{
+ struct snd_sof_dfsentry *dfse;
+
+ dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+ if (!dfse)
+ return -ENOMEM;
+
+ dfse->type = SOF_DFSENTRY_TYPE_BUF;
+ dfse->sdev = sdev;
+
+ debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops);
+ /* add to dfsentry list */
+ list_add(&dfse->list, &sdev->dfsentry_list);
+
+ return 0;
+}
+#endif
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
#define MAX_IPC_FLOOD_DURATION_MS 1000
#define MAX_IPC_FLOOD_COUNT 10000
@@ -436,6 +651,17 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
return err;
}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
+ err = snd_sof_debugfs_probe_item(sdev, "probe_points",
+ 0644, &probe_points_fops);
+ if (err < 0)
+ return err;
+ err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove",
+ 0200, &probe_points_remove_fops);
+ if (err < 0)
+ return err;
+#endif
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
/* create read-write ipc_flood_count debugfs entry */
err = snd_sof_debugfs_buf_item(sdev, NULL, 0,