Skip to content

Commit 8e378ea

Browse files
committed
ASoC: Intel: avs: Data probing and fw logging
Merge series from Cezary Rojewski <[email protected]>: The patchset focuses on debug functionality for the avs-driver. Two major blocks are covered here: data probing and AudioDSP firmware logging. Both are configured and controlled through debugfs. Data probing is a AudioDSP debug functionality which allows for gathering the actual data that is being routed to or from a module. Helps in debugging its processing capabilities - navigate to a specific module which may have caused a glitch within a pipeline (set of modules bound together). First few allow for assigning compress stream to a HDAudio stream, what is currently limited to pcm substreams only. These patches were already present on this list and reviewed in the past [1]. The next few tidy existing debug-related code up so it's ready for addition of new functionalities and make it clear which part of the avs is debug related and which is not. These also simplify the existing locking around the trace fifo. Afterward, debug-related IPCs are defined along with stub soc-component and compress DAI operations. Not much is done there as it's not a standard PCM streaming scenario. Most code found in compress operations is inherited from the HOST side of HDAudio streaming found in pcm.c file of the driver. Finally, a debugfs file operations are defined. These facilitate connecting to DSP modules from which the data shall be gathered as well as control and configuration of firmware logging. Additionally, entries are added to allow for dumping snapshots of key memory windows.
2 parents 1b41bea + 85ac9c8 commit 8e378ea

File tree

22 files changed

+1172
-100
lines changed

22 files changed

+1172
-100
lines changed

include/sound/hdaudio_ext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
7575
struct snd_pcm_substream *substream,
7676
int type);
7777
void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type);
78+
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
79+
struct snd_compr_stream *cstream);
7880
void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
7981
struct hdac_ext_stream *hext_stream, bool decouple);
8082
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,

sound/hda/ext/hdac_ext_stream.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <sound/pcm.h>
1515
#include <sound/hda_register.h>
1616
#include <sound/hdaudio_ext.h>
17+
#include <sound/compress_driver.h>
1718

1819
/**
1920
* snd_hdac_ext_stream_init - initialize each stream (aka device)
@@ -367,3 +368,43 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
367368

368369
}
369370
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
371+
372+
/**
373+
* snd_hdac_ext_cstream_assign - assign a host stream for compress
374+
* @bus: HD-audio core bus
375+
* @cstream: Compress stream to assign
376+
*
377+
* Assign an unused host stream for the given compress stream.
378+
* If no stream is free, NULL is returned. Stream is decoupled
379+
* before assignment.
380+
*/
381+
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
382+
struct snd_compr_stream *cstream)
383+
{
384+
struct hdac_ext_stream *res = NULL;
385+
struct hdac_stream *hstream;
386+
387+
spin_lock_irq(&bus->reg_lock);
388+
list_for_each_entry(hstream, &bus->stream_list, list) {
389+
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
390+
391+
if (hstream->direction != cstream->direction)
392+
continue;
393+
394+
if (!hstream->opened) {
395+
res = hext_stream;
396+
break;
397+
}
398+
}
399+
400+
if (res) {
401+
snd_hdac_ext_stream_decouple_locked(bus, res, true);
402+
res->hstream.opened = 1;
403+
res->hstream.running = 0;
404+
res->hstream.cstream = cstream;
405+
}
406+
spin_unlock_irq(&bus->reg_lock);
407+
408+
return res;
409+
}
410+
EXPORT_SYMBOL_GPL(snd_hdac_ext_cstream_assign);

sound/hda/hdac_controller.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,8 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
578578
sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
579579
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
580580
handled |= 1 << azx_dev->index;
581-
if (!azx_dev->substream || !azx_dev->running ||
582-
!(sd_status & SD_INT_COMPLETE))
581+
if ((!azx_dev->substream && !azx_dev->cstream) ||
582+
!azx_dev->running || !(sd_status & SD_INT_COMPLETE))
583583
continue;
584584
if (ack)
585585
ack(bus, azx_dev);

sound/hda/hdac_stream.c

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/delay.h>
88
#include <linux/export.h>
99
#include <linux/clocksource.h>
10+
#include <sound/compress_driver.h>
1011
#include <sound/core.h>
1112
#include <sound/pcm.h>
1213
#include <sound/hdaudio.h>
@@ -487,11 +488,20 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
487488
{
488489
struct hdac_bus *bus = azx_dev->bus;
489490
struct snd_pcm_substream *substream = azx_dev->substream;
490-
struct snd_pcm_runtime *runtime = substream->runtime;
491+
struct snd_compr_stream *cstream = azx_dev->cstream;
492+
struct snd_pcm_runtime *runtime = NULL;
493+
struct snd_dma_buffer *dmab;
491494
__le32 *bdl;
492495
int i, ofs, periods, period_bytes;
493496
int pos_adj, pos_align;
494497

498+
if (substream) {
499+
runtime = substream->runtime;
500+
dmab = snd_pcm_get_dma_buf(substream);
501+
} else if (cstream) {
502+
dmab = snd_pcm_get_dma_buf(cstream);
503+
}
504+
495505
/* reset BDL address */
496506
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
497507
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
@@ -505,7 +515,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
505515
azx_dev->frags = 0;
506516

507517
pos_adj = bus->bdl_pos_adj;
508-
if (!azx_dev->no_period_wakeup && pos_adj > 0) {
518+
if (runtime && !azx_dev->no_period_wakeup && pos_adj > 0) {
509519
pos_align = pos_adj;
510520
pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000);
511521
if (!pos_adj)
@@ -518,8 +528,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
518528
pos_adj);
519529
pos_adj = 0;
520530
} else {
521-
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
522-
azx_dev,
531+
ofs = setup_bdle(bus, dmab, azx_dev,
523532
&bdl, ofs, pos_adj, true);
524533
if (ofs < 0)
525534
goto error;
@@ -529,13 +538,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
529538

530539
for (i = 0; i < periods; i++) {
531540
if (i == periods - 1 && pos_adj)
532-
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
533-
azx_dev, &bdl, ofs,
534-
period_bytes - pos_adj, 0);
541+
ofs = setup_bdle(bus, dmab, azx_dev,
542+
&bdl, ofs, period_bytes - pos_adj, 0);
535543
else
536-
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
537-
azx_dev, &bdl, ofs,
538-
period_bytes,
544+
ofs = setup_bdle(bus, dmab, azx_dev,
545+
&bdl, ofs, period_bytes,
539546
!azx_dev->no_period_wakeup);
540547
if (ofs < 0)
541548
goto error;
@@ -560,26 +567,32 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
560567
int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
561568
unsigned int format_val)
562569
{
563-
564-
unsigned int bufsize, period_bytes;
565570
struct snd_pcm_substream *substream = azx_dev->substream;
566-
struct snd_pcm_runtime *runtime;
571+
struct snd_compr_stream *cstream = azx_dev->cstream;
572+
unsigned int bufsize, period_bytes;
573+
unsigned int no_period_wakeup;
567574
int err;
568575

569-
if (!substream)
576+
if (substream) {
577+
bufsize = snd_pcm_lib_buffer_bytes(substream);
578+
period_bytes = snd_pcm_lib_period_bytes(substream);
579+
no_period_wakeup = substream->runtime->no_period_wakeup;
580+
} else if (cstream) {
581+
bufsize = cstream->runtime->buffer_size;
582+
period_bytes = cstream->runtime->fragment_size;
583+
no_period_wakeup = 0;
584+
} else {
570585
return -EINVAL;
571-
runtime = substream->runtime;
572-
bufsize = snd_pcm_lib_buffer_bytes(substream);
573-
period_bytes = snd_pcm_lib_period_bytes(substream);
586+
}
574587

575588
if (bufsize != azx_dev->bufsize ||
576589
period_bytes != azx_dev->period_bytes ||
577590
format_val != azx_dev->format_val ||
578-
runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
591+
no_period_wakeup != azx_dev->no_period_wakeup) {
579592
azx_dev->bufsize = bufsize;
580593
azx_dev->period_bytes = period_bytes;
581594
azx_dev->format_val = format_val;
582-
azx_dev->no_period_wakeup = runtime->no_period_wakeup;
595+
azx_dev->no_period_wakeup = no_period_wakeup;
583596
err = snd_hdac_stream_setup_periods(azx_dev);
584597
if (err < 0)
585598
return err;

sound/soc/intel/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS
217217
select SND_SOC_ACPI if ACPI
218218
select SND_SOC_TOPOLOGY
219219
select SND_SOC_HDA
220+
select SND_SOC_COMPRESS if DEBUG_FS
220221
select SND_HDA_EXT_CORE
221222
select SND_HDA_DSP_LOADER
222223
select SND_INTEL_DSP_CONFIG

sound/soc/intel/avs/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o
99
# tell define_trace.h where to find the trace header
1010
CFLAGS_trace.o := -I$(src)
1111

12+
ifneq ($(CONFIG_DEBUG_FS),)
13+
snd-soc-avs-objs += probes.o debugfs.o
14+
endif
15+
1216
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
1317

1418
# Machine support

sound/soc/intel/avs/apl.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
#include "path.h"
1414
#include "topology.h"
1515

16-
static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
17-
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
16+
static int __maybe_unused
17+
apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
18+
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
1819
{
1920
struct apl_log_state_info *info;
2021
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
5051
static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
5152
{
5253
struct apl_log_buffer_layout layout;
53-
unsigned long flags;
5454
void __iomem *addr, *buf;
5555

5656
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
5959

6060
memcpy_fromio(&layout, addr, sizeof(layout));
6161

62-
spin_lock_irqsave(&adev->dbg.trace_lock, flags);
63-
if (!kfifo_initialized(&adev->dbg.trace_fifo))
62+
if (!avs_logging_fw(adev))
6463
/* consume the logs regardless of consumer presence */
6564
goto update_read_ptr;
6665

6766
buf = apl_log_payload_addr(addr);
6867

6968
if (layout.read_ptr > layout.write_ptr) {
70-
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
71-
apl_log_payload_size(adev) - layout.read_ptr,
72-
&adev->dbg.fifo_lock);
69+
avs_dump_fw_log(adev, buf + layout.read_ptr,
70+
apl_log_payload_size(adev) - layout.read_ptr);
7371
layout.read_ptr = 0;
7472
}
75-
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
76-
layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
77-
78-
wake_up(&adev->dbg.trace_waitq);
73+
avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
7974

8075
update_read_ptr:
81-
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
8276
writel(layout.write_ptr, addr);
8377
return 0;
8478
}
@@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
140134
* gathered before dumping stack
141135
*/
142136
lbs_msg.log.core = msg->ext.coredump.core_id;
143-
avs_dsp_op(adev, log_buffer_status, &lbs_msg);
137+
avs_log_buffer_status_locked(adev, &lbs_msg);
144138
}
145139

146140
pos = dump + AVS_FW_REGS_SIZE;
@@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = {
243237
.load_basefw = avs_hda_load_basefw,
244238
.load_lib = avs_hda_load_library,
245239
.transfer_mods = avs_hda_transfer_modules,
246-
.enable_logs = apl_enable_logs,
247240
.log_buffer_offset = skl_log_buffer_offset,
248241
.log_buffer_status = apl_log_buffer_status,
249242
.coredump = apl_coredump,
250243
.d0ix_toggle = apl_d0ix_toggle,
251244
.set_d0ix = apl_set_d0ix,
245+
AVS_SET_ENABLE_LOGS_OP(apl)
252246
};

sound/soc/intel/avs/avs.h

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef __SOUND_SOC_INTEL_AVS_H
1010
#define __SOUND_SOC_INTEL_AVS_H
1111

12+
#include <linux/debugfs.h>
1213
#include <linux/device.h>
1314
#include <linux/firmware.h>
1415
#include <linux/kfifo.h>
@@ -93,16 +94,6 @@ struct avs_fw_entry {
9394
struct list_head node;
9495
};
9596

96-
struct avs_debug {
97-
struct kfifo trace_fifo;
98-
spinlock_t fifo_lock; /* serialize I/O for trace_fifo */
99-
spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
100-
wait_queue_head_t trace_waitq;
101-
u32 aging_timer_period;
102-
u32 fifo_full_timer_period;
103-
u32 logged_resources; /* context dependent: core or library */
104-
};
105-
10697
/*
10798
* struct avs_dev - Intel HD-Audio driver data
10899
*
@@ -146,7 +137,18 @@ struct avs_dev {
146137
spinlock_t path_list_lock;
147138
struct mutex path_mutex;
148139

149-
struct avs_debug dbg;
140+
spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
141+
#ifdef CONFIG_DEBUG_FS
142+
struct kfifo trace_fifo;
143+
wait_queue_head_t trace_waitq;
144+
u32 aging_timer_period;
145+
u32 fifo_full_timer_period;
146+
u32 logged_resources; /* context dependent: core or library */
147+
struct dentry *debugfs_root;
148+
/* probes */
149+
struct hdac_ext_stream *extractor;
150+
unsigned int num_probe_streams;
151+
#endif
150152
};
151153

152154
/* from hda_bus to avs_dev */
@@ -321,6 +323,9 @@ struct avs_soc_component {
321323

322324
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
323325

326+
int avs_soc_component_register(struct device *dev, const char *name,
327+
const struct snd_soc_component_driver *drv,
328+
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
324329
int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
325330
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
326331
unsigned long *tdms);
@@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev);
331336

332337
/* Firmware tracing helpers */
333338

334-
unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
335-
spinlock_t *lock);
336-
337339
#define avs_log_buffer_size(adev) \
338340
((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
339341

@@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
344346
(avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
345347
})
346348

349+
static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
350+
{
351+
unsigned long flags;
352+
int ret;
353+
354+
spin_lock_irqsave(&adev->trace_lock, flags);
355+
ret = avs_dsp_op(adev, log_buffer_status, msg);
356+
spin_unlock_irqrestore(&adev->trace_lock, flags);
357+
358+
return ret;
359+
}
360+
347361
struct apl_log_buffer_layout {
348362
u32 read_ptr;
349363
u32 write_ptr;
@@ -356,4 +370,42 @@ struct apl_log_buffer_layout {
356370
#define apl_log_payload_addr(addr) \
357371
(addr + sizeof(struct apl_log_buffer_layout))
358372

373+
#ifdef CONFIG_DEBUG_FS
374+
#define AVS_SET_ENABLE_LOGS_OP(name) \
375+
.enable_logs = name##_enable_logs
376+
377+
bool avs_logging_fw(struct avs_dev *adev);
378+
void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
379+
void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
380+
381+
int avs_probe_platform_register(struct avs_dev *adev, const char *name);
382+
383+
void avs_debugfs_init(struct avs_dev *adev);
384+
void avs_debugfs_exit(struct avs_dev *adev);
385+
#else
386+
#define AVS_SET_ENABLE_LOGS_OP(name)
387+
388+
static inline bool avs_logging_fw(struct avs_dev *adev)
389+
{
390+
return false;
391+
}
392+
393+
static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
394+
{
395+
}
396+
397+
static inline void
398+
avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
399+
{
400+
}
401+
402+
static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name)
403+
{
404+
return 0;
405+
}
406+
407+
static inline void avs_debugfs_init(struct avs_dev *adev) { }
408+
static inline void avs_debugfs_exit(struct avs_dev *adev) { }
409+
#endif
410+
359411
#endif /* __SOUND_SOC_INTEL_AVS_H */

0 commit comments

Comments
 (0)