diff options
Diffstat (limited to 'sound/soc')
39 files changed, 1303 insertions, 579 deletions
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 4c7ebc7fb400..a75db27e5205 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, ctrl->clsh_users = 0; } -static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) -{ - return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) & - WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; -} - static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, int mode) { diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 50b71e5d4589..582f1e2431ee 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -75,8 +75,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", - pdcr, ptcr); + ret = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) ret += scnprintf(buf + ret, PAGE_SIZE - ret, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fe7cf972d44c..5daa824a4ffc 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -485,8 +485,10 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv, of_node_put(codec_ep); of_node_put(codec_port); - if (ret < 0) + if (ret < 0) { + of_node_put(cpu_ep); return ret; + } codec_port_old = codec_port; } diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index ac799de4f7fd..4b9e498e3303 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS select SND_SOC_ACPI if ACPI select SND_SOC_TOPOLOGY select SND_SOC_HDA + select SND_SOC_COMPRESS if DEBUG_FS select SND_HDA_EXT_CORE select SND_HDA_DSP_LOADER select SND_INTEL_DSP_CONFIG diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 919212825f21..1c6924a1ebca 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o # tell define_trace.h where to find the trace header CFLAGS_trace.o := -I$(src) +ifneq ($(CONFIG_DEBUG_FS),) +snd-soc-avs-objs += probes.o debugfs.o +endif + obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o # Machine support diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index 7c8ce98eda9d..02683dce277a 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -13,8 +13,9 @@ #include "path.h" #include "topology.h" -static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, - u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) +static int __maybe_unused +apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, + u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) { struct apl_log_state_info *info; u32 size, num_cores = adev->hw_cfg.dsp_cores; @@ -50,7 +51,6 @@ static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg) { struct apl_log_buffer_layout layout; - unsigned long flags; void __iomem *addr, *buf; addr = avs_log_buffer_addr(adev, msg->log.core); @@ -59,26 +59,20 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg memcpy_fromio(&layout, addr, sizeof(layout)); - spin_lock_irqsave(&adev->dbg.trace_lock, flags); - if (!kfifo_initialized(&adev->dbg.trace_fifo)) + if (!avs_logging_fw(adev)) /* consume the logs regardless of consumer presence */ goto update_read_ptr; buf = apl_log_payload_addr(addr); if (layout.read_ptr > layout.write_ptr) { - __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr, - apl_log_payload_size(adev) - layout.read_ptr, - &adev->dbg.fifo_lock); + avs_dump_fw_log(adev, buf + layout.read_ptr, + apl_log_payload_size(adev) - layout.read_ptr); layout.read_ptr = 0; } - __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr, - layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock); - - wake_up(&adev->dbg.trace_waitq); + avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr); update_read_ptr: - spin_unlock_irqrestore(&adev->dbg.trace_lock, flags); writel(layout.write_ptr, addr); return 0; } @@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) * gathered before dumping stack */ lbs_msg.log.core = msg->ext.coredump.core_id; - avs_dsp_op(adev, log_buffer_status, &lbs_msg); + avs_log_buffer_status_locked(adev, &lbs_msg); } pos = dump + AVS_FW_REGS_SIZE; @@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = { .load_basefw = avs_hda_load_basefw, .load_lib = avs_hda_load_library, .transfer_mods = avs_hda_transfer_modules, - .enable_logs = apl_enable_logs, .log_buffer_offset = skl_log_buffer_offset, .log_buffer_status = apl_log_buffer_status, .coredump = apl_coredump, .d0ix_toggle = apl_d0ix_toggle, .set_d0ix = apl_set_d0ix, + AVS_SET_ENABLE_LOGS_OP(apl) }; diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 8d05b27608fe..d7fccdcb9c16 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -9,6 +9,7 @@ #ifndef __SOUND_SOC_INTEL_AVS_H #define __SOUND_SOC_INTEL_AVS_H +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/firmware.h> #include <linux/kfifo.h> @@ -93,16 +94,6 @@ struct avs_fw_entry { struct list_head node; }; -struct avs_debug { - struct kfifo trace_fifo; - spinlock_t fifo_lock; /* serialize I/O for trace_fifo */ - spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */ - wait_queue_head_t trace_waitq; - u32 aging_timer_period; - u32 fifo_full_timer_period; - u32 logged_resources; /* context dependent: core or library */ -}; - /* * struct avs_dev - Intel HD-Audio driver data * @@ -146,7 +137,18 @@ struct avs_dev { spinlock_t path_list_lock; struct mutex path_mutex; - struct avs_debug dbg; + spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */ +#ifdef CONFIG_DEBUG_FS + struct kfifo trace_fifo; + wait_queue_head_t trace_waitq; + u32 aging_timer_period; + u32 fifo_full_timer_period; + u32 logged_resources; /* context dependent: core or library */ + struct dentry *debugfs_root; + /* probes */ + struct hdac_ext_stream *extractor; + unsigned int num_probe_streams; +#endif }; /* from hda_bus to avs_dev */ @@ -321,6 +323,9 @@ struct avs_soc_component { extern const struct snd_soc_dai_ops avs_dai_fe_ops; +int avs_soc_component_register(struct device *dev, const char *name, + const struct snd_soc_component_driver *drv, + struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); int avs_dmic_platform_register(struct avs_dev *adev, const char *name); int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, unsigned long *tdms); @@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev); /* Firmware tracing helpers */ -unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len, - spinlock_t *lock); - #define avs_log_buffer_size(adev) \ ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) @@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ }) +static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&adev->trace_lock, flags); + ret = avs_dsp_op(adev, log_buffer_status, msg); + spin_unlock_irqrestore(&adev->trace_lock, flags); + + return ret; +} + struct apl_log_buffer_layout { u32 read_ptr; u32 write_ptr; @@ -356,4 +370,42 @@ struct apl_log_buffer_layout { #define apl_log_payload_addr(addr) \ (addr + sizeof(struct apl_log_buffer_layout)) +#ifdef CONFIG_DEBUG_FS +#define AVS_SET_ENABLE_LOGS_OP(name) \ + .enable_logs = name##_enable_logs + +bool avs_logging_fw(struct avs_dev *adev); +void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); +void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len); + +int avs_probe_platform_register(struct avs_dev *adev, const char *name); + +void avs_debugfs_init(struct avs_dev *adev); +void avs_debugfs_exit(struct avs_dev *adev); +#else +#define AVS_SET_ENABLE_LOGS_OP(name) + +static inline bool avs_logging_fw(struct avs_dev *adev) +{ + return false; +} + +static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ +} + +static inline void +avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ +} + +static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name) +{ + return 0; +} + +static inline void avs_debugfs_init(struct avs_dev *adev) { } +static inline void avs_debugfs_exit(struct avs_dev *adev) { } +#endif + #endif /* __SOUND_SOC_INTEL_AVS_H */ diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 02cc1ce8f5f5..b2823c2107f7 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -291,6 +291,33 @@ static void board_pdev_unregister(void *data) platform_device_unregister(data); } +static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) +{ + struct platform_device *board; + struct snd_soc_acpi_mach mach = {{0}}; + int ret; + + ret = avs_probe_platform_register(adev, "probe-platform"); + if (ret < 0) + return ret; + + mach.mach_params.platform = "probe-platform"; + + board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE, + (const void *)&mach, sizeof(mach)); + if (IS_ERR(board)) { + dev_err(adev->dev, "probe board register failed\n"); + return PTR_ERR(board); + } + + ret = devm_add_action(adev->dev, board_pdev_unregister, board); + if (ret < 0) { + platform_device_unregister(board); + return ret; + } + return 0; +} + static int avs_register_dmic_board(struct avs_dev *adev) { struct platform_device *codec, *board; @@ -500,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev) { int ret; +#ifdef CONFIG_DEBUG_FS + ret = avs_register_probe_board(adev); + if (ret < 0) + dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret); +#endif + ret = avs_register_dmic_board(adev); if (ret < 0) dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n", diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index 9bd40fdd9028..e4c230efe8d7 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -77,6 +77,14 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_PROBE + tristate "Probing (data) board" + depends on DEBUG_FS + select SND_HWDEP + help + This adds support for data probing board which can be used to + gather data from runtime stream over compress operations. + config SND_SOC_INTEL_AVS_MACH_RT274 tristate "rt274 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index 4d70b8d09ce5..b81343420370 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -8,6 +8,7 @@ snd-soc-avs-max98927-objs := max98927.o snd-soc-avs-max98357a-objs := max98357a.o snd-soc-avs-max98373-objs := max98373.o snd-soc-avs-nau8825-objs := nau8825.o +snd-soc-avs-probe-objs := probe.o snd-soc-avs-rt274-objs := rt274.o snd-soc-avs-rt286-objs := rt286.o snd-soc-avs-rt298-objs := rt298.o @@ -22,6 +23,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c new file mode 100644 index 000000000000..411acaee74f9 --- /dev/null +++ b/sound/soc/intel/avs/boards/probe.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/device.h> +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> + +SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); +SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI"))); +SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform"))); + +static struct snd_soc_dai_link probe_mb_dai_links[] = { + { + .name = "Compress Probe Capture", + .nonatomic = 1, + SND_SOC_DAILINK_REG(probe_cp, dummy, platform), + }, +}; + +static int avs_probe_mb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + int ret; + + mach = dev_get_platdata(dev); + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "avs_probe_mb"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dai_link = probe_mb_dai_links; + card->num_links = ARRAY_SIZE(probe_mb_dai_links); + card->fully_routed = true; + + ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_probe_mb_driver = { + .probe = avs_probe_mb_probe, + .driver = { + .name = "avs_probe_mb", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_probe_mb_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_probe_mb"); diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index f7bc06404dbc..2ca24273c491 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -214,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work) adev->nhlt = intel_nhlt_init(adev->dev); if (!adev->nhlt) dev_info(bus->dev, "platform has no NHLT\n"); + avs_debugfs_init(adev); avs_register_all_boards(adev); @@ -491,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci) avs_unregister_all_boards(adev); + avs_debugfs_exit(adev); if (adev->nhlt) intel_nhlt_free(adev->nhlt); diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c new file mode 100644 index 000000000000..bdd388ec01ea --- /dev/null +++ b/sound/soc/intel/avs/debugfs.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/debugfs.h> +#include <linux/kfifo.h> +#include <linux/wait.h> +#include <linux/sched/signal.h> +#include <sound/soc.h> +#include "avs.h" +#include "messages.h" + +static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len) +{ + struct __kfifo *__fifo = &fifo->kfifo; + unsigned int l, off; + + len = min(len, kfifo_avail(fifo)); + off = __fifo->in & __fifo->mask; + l = min(len, kfifo_size(fifo) - off); + + memcpy_fromio(__fifo->data + off, src, l); + memcpy_fromio(__fifo->data, src + l, len - l); + /* Make sure data copied from SRAM is visible to all CPUs. */ + smp_mb(); + __fifo->in += len; + + return len; +} + +bool avs_logging_fw(struct avs_dev *adev) +{ + return kfifo_initialized(&adev->trace_fifo); +} + +void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ + __kfifo_fromio(&adev->trace_fifo, src, len); +} + +void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ + avs_dump_fw_log(adev, src, len); + wake_up(&adev->trace_waitq); +} + +static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct avs_dev *adev = file->private_data; + char *buf; + int ret; + + buf = kzalloc(AVS_FW_REGS_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy_fromio(buf, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE); + + ret = simple_read_from_buffer(to, count, ppos, buf, AVS_FW_REGS_SIZE); + kfree(buf); + return ret; +} + +static const struct file_operations fw_regs_fops = { + .open = simple_open, + .read = fw_regs_read, + .llseek = no_llseek, +}; + +static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct avs_dev *adev = file->private_data; + size_t size; + char *buf; + int ret; + + size = adev->hw_cfg.dsp_cores * AVS_WINDOW_CHUNK_SIZE; + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy_fromio(buf, avs_sram_addr(adev, AVS_DEBUG_WINDOW), size); + + ret = simple_read_from_buffer(to, count, ppos, buf, size); + kfree(buf); + return ret; +} + +static const struct file_operations debug_window_fops = { + .open = simple_open, + .read = debug_window_read, + .llseek = no_llseek, +}; + +static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct avs_dev *adev = file->private_data; + struct avs_probe_point_desc *desc; + size_t num_desc, len = 0; + char *buf; + int i, ret; + + /* Prevent chaining, send and dump IPC value just once. */ + if (*ppos) + return 0; + + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = avs_ipc_probe_get_points(adev, &desc, &num_desc); + if (ret) { + ret = AVS_IPC_RET(ret); + 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].id.value, desc[i].purpose, desc[i].node_id.val); + 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 avs_dev *adev = file->private_data; + struct avs_probe_point_desc *desc; + u32 *array, num_elems; + size_t bytes; + int ret; + + ret = parse_int_array_user(from, count, (int **)&array); + if (ret < 0) + return ret; + + num_elems = *array; + bytes = sizeof(*array) * num_elems; + if (bytes % sizeof(*desc)) { + ret = -EINVAL; + goto exit; + } + + desc = (struct avs_probe_point_desc *)&array[1]; + ret = avs_ipc_probe_connect_points(adev, desc, bytes / sizeof(*desc)); + if (ret) + ret = AVS_IPC_RET(ret); + else + ret = count; +exit: + kfree(array); + return ret; +} + +static const struct file_operations probe_points_fops = { + .open = simple_open, + .read = probe_points_read, + .write = probe_points_write, + .llseek = no_llseek, +}; + +static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from, + size_t count, loff_t *ppos) +{ + struct avs_dev *adev = file->private_data; + union avs_probe_point_id *id; + u32 *array, num_elems; + size_t bytes; + int ret; + + ret = parse_int_array_user(from, count, (int **)&array); + if (ret < 0) + return ret; + + num_elems = *array; + bytes = sizeof(*array) * num_elems; + if (bytes % sizeof(*id)) { + ret = -EINVAL; + goto exit; + } + + id = (union avs_probe_point_id *)&array[1]; + ret = avs_ipc_probe_disconnect_points(adev, id, bytes / sizeof(*id)); + if (ret) + ret = AVS_IPC_RET(ret); + else + ret = count; +exit: + kfree(array); + return ret; +} + +static const struct file_operations probe_points_disconnect_fops = { + .open = simple_open, + .write = probe_points_disconnect_write, + .llseek = default_llseek, +}; + +static ssize_t strace_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct avs_dev *adev = file->private_data; + struct kfifo *fifo = &adev->trace_fifo; + unsigned int copied; + + if (kfifo_is_empty(fifo)) { + DEFINE_WAIT(wait); + + prepare_to_wait(&adev->trace_waitq, &wait, TASK_INTERRUPTIBLE); + if (!signal_pending(current)) + schedule(); + finish_wait(&adev->trace_waitq, &wait); + } + + if (kfifo_to_user(fifo, to, count, &copied)) + return -EFAULT; + *ppos += copied; + return copied; +} + +static int strace_open(struct inode *inode, struct file *file) +{ + struct avs_dev *adev = inode->i_private; + int ret; + + if (kfifo_initialized(&adev->trace_fifo)) + return -EBUSY; + + ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL); + if (ret < 0) + return ret; + + file->private_data = adev; + return 0; +} + +static int strace_release(struct inode *inode, struct file *file) +{ + union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS); + struct avs_dev *adev = file->private_data; + unsigned long resource_mask; + unsigned long flags, i; + u32 num_cores; + + resource_mask = adev->logged_resources; + num_cores = adev->hw_cfg.dsp_cores; + + spin_lock_irqsave(&adev->trace_lock, flags); + + /* Gather any remaining logs. */ + for_each_set_bit(i, &resource_mask, num_cores) { + msg.log.core = i; + avs_dsp_op(adev, log_buffer_status, &msg); + } + + kfifo_free(&adev->trace_fifo); + + spin_unlock_irqrestore(&adev->trace_lock, flags); + + return 0; +} + +static const struct file_operations strace_fops = { + .llseek = default_llseek, + .read = strace_read, + .open = strace_open, + .release = strace_release, +}; + +#define DISABLE_TIMERS UINT_MAX + +static int enable_logs(struct avs_dev *adev, u32 resource_mask, u32 *priorities) +{ + int ret; + + /* Logging demands D0i0 state from DSP. */ + if (!adev->logged_resources) { + pm_runtime_get_sync(adev->dev); + + ret = avs_dsp_disable_d0ix(adev); + if (ret) + goto err_d0ix; + } + + ret = avs_ipc_set_system_time(adev); + if (ret && ret != AVS_IPC_NOT_SUPPORTED) { + ret = AVS_IPC_RET(ret); + goto err_ipc; + } + + ret = avs_dsp_op(adev, enable_logs, AVS_LOG_ENABLE, adev->aging_timer_period, + adev->fifo_full_timer_period, resource_mask, priorities); + if (ret) + goto err_ipc; + + adev->logged_resources |= resource_mask; + return 0; + +err_ipc: + |
