Skip to content

Commit 593520e

Browse files
committed
ASoC: SOF: trace: fix trace is cleared after suspend/resume issue
We have issues for DMA trace if runtime suspend is turned on, those logs before suspend will be cleared/overwritten after resume. To fix the issue, this commit change the DMA trace behavior as below: We add a member trace_init_offset to store the last trace offset beforei suspend, and calculate the available log size based on it. We also extend hda_dsp_stream_setup_bdl() to support non-0 offset, which is needed for trace BDL setup. This make FW possible to copy new logs to destination from trace_init_offset, which won't overwrite the existed logs before suspend. With these changes, the issue mentioned above is resolved on APL. Todo: for SKL- platforms where not using BDL entries, FW to support non-0 offset need to be implemented for those platforms, please refer to this: thesofproject/sof#544 Signed-off-by: Keyon Jie <yang.jie@linux.intel.com>
1 parent 2848117 commit 593520e

File tree

7 files changed

+103
-40
lines changed

7 files changed

+103
-40
lines changed

sound/soc/sof/intel/hda-loader.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
6666
hstream->format_val = format;
6767
hstream->bufsize = size;
6868

69-
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
69+
ret = hda_dsp_stream_hw_params(sdev, stream, dmab,
70+
NULL, SOF_HDA_CL_STREAM);
7071
if (ret < 0) {
7172
dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
7273
goto error;

sound/soc/sof/intel/hda-pcm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
121121
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
122122
(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
123123

124-
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
124+
ret = hda_dsp_stream_hw_params(sdev, stream, dmab,
125+
params, SOF_HDA_AUDIO_STREAM);
125126
if (ret < 0) {
126127
dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
127128
return ret;

sound/soc/sof/intel/hda-stream.c

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -88,31 +88,46 @@ static int hda_setup_bdle(struct snd_sof_dev *sdev,
8888
/*
8989
* set up Buffer Descriptor List (BDL) for host memory transfer
9090
* BDL describes the location of the individual buffers and is little endian.
91+
*
92+
* The typical BDL entries after set up should looks like this:
93+
*
94+
* bdl[0] from the init_offset, n entries before wrap,
95+
* the e-1 full entries, and the last e entry.
96+
*
97+
* init_offset
98+
* |
99+
* |------|...........|---------S-------|------|........|--------|-------|
100+
* bdl[n] bdl[n+j] bdl[e-1] | bdl[0] bdl[1] bdl[m] bdl[n-2] bdl[n-1]
91101
*/
92102
int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
93103
struct snd_dma_buffer *dmab,
94-
struct hdac_stream *stream)
104+
struct hdac_stream *stream, u32 init_offset)
95105
{
96106
struct sof_intel_dsp_bdl *bdl;
97-
int i, offset, period_bytes, periods;
98-
int remain, ioc;
107+
unsigned int i, period_bytes, entries;
108+
u32 bytes, offset, size = 0;
109+
bool ioc, set_ioc, is_wrap = false;
99110

100111
period_bytes = stream->period_bytes;
101112
dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
102113
if (!period_bytes)
103114
period_bytes = stream->bufsize;
104115

105-
periods = stream->bufsize / period_bytes;
116+
entries = stream->bufsize / period_bytes;
106117

107-
dev_dbg(sdev->dev, "periods:%d\n", periods);
118+
/* count the last offset fragment entry */
119+
if (stream->bufsize % period_bytes)
120+
entries++;
108121

109-
remain = stream->bufsize % period_bytes;
110-
if (remain)
111-
periods++;
122+
/* count the last index fragment entry */
123+
if (init_offset % period_bytes)
124+
entries++;
125+
126+
dev_dbg(sdev->dev, "entries:%d\n", entries);
112127

113128
/* program the initial BDL entries */
114129
bdl = (struct sof_intel_dsp_bdl *)stream->bdl.area;
115-
offset = 0;
130+
offset = init_offset;
116131
stream->frags = 0;
117132

118133
/*
@@ -122,19 +137,28 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
122137
ioc = sdev->hda->no_ipc_position ?
123138
!stream->no_period_wakeup : 0;
124139

125-
for (i = 0; i < periods; i++) {
126-
if (i == (periods - 1) && remain)
127-
/* set the last small entry */
128-
offset = hda_setup_bdle(sdev, dmab,
129-
stream, &bdl, offset,
130-
remain, 0);
140+
for (i = 0; i < entries; i++) {
141+
bytes = period_bytes - offset % period_bytes;
142+
if (is_wrap)
143+
bytes = min(bytes, init_offset - offset);
131144
else
132-
offset = hda_setup_bdle(sdev, dmab,
133-
stream, &bdl, offset,
134-
period_bytes, ioc);
145+
bytes = min(bytes, stream->bufsize - offset);
146+
147+
/* only set ioc at period bundary */
148+
set_ioc = (offset + bytes) % period_bytes ? 0 : 1;
149+
offset = hda_setup_bdle(sdev, dmab,
150+
stream, &bdl, offset,
151+
bytes, set_ioc && ioc);
152+
153+
if (offset == stream->bufsize) {
154+
offset = 0;
155+
is_wrap = true;
156+
}
157+
158+
size += bytes;
135159
}
136160

137-
return offset;
161+
return size;
138162
}
139163

140164
int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
@@ -344,19 +368,21 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
344368
}
345369

346370
/*
347-
* prepare for common hdac registers settings, for both code loader
371+
* prepare for common hdac registers settings, for code loader, dma trace,
348372
* and normal stream.
349373
*/
350374
int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
351375
struct hdac_ext_stream *stream,
352376
struct snd_dma_buffer *dmab,
353-
struct snd_pcm_hw_params *params)
377+
struct snd_pcm_hw_params *params,
378+
enum sof_hda_tream_type stream_type)
354379
{
355380
struct hdac_bus *bus = sof_to_bus(sdev);
356381
struct hdac_stream *hstream = &stream->hstream;
357382
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
358383
int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT;
359384
u32 val, mask;
385+
u32 init_offset = 0;
360386

361387
if (!stream) {
362388
dev_err(sdev->dev, "error: no stream available\n");
@@ -436,10 +462,13 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
436462

437463
hstream->frags = 0;
438464

439-
ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream);
440-
if (ret < 0) {
441-
dev_err(sdev->dev, "error: set up of BDL failed\n");
442-
return ret;
465+
if (stream_type == SOF_HDA_TRACE_STREAM)
466+
init_offset = sdev->trace_init_offset;
467+
468+
ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream, init_offset);
469+
if (ret != hstream->bufsize) {
470+
dev_err(sdev->dev, "error: set up of BDL failed, bufsize:0x%x, only 0x%x set\n", hstream->bufsize, ret);
471+
return -EFAULT;
443472
}
444473

445474
/* set up stream descriptor for DMA */

sound/soc/sof/intel/hda-trace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev)
4343

4444
hstream->bufsize = sdev->dmatb.bytes;
4545

46-
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
46+
ret = hda_dsp_stream_hw_params(sdev, stream, dmab,
47+
NULL, SOF_HDA_TRACE_STREAM);
4748
if (ret < 0)
4849
dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
4950

sound/soc/sof/intel/hda.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,12 @@ struct sof_intel_dsp_desc {
343343
struct snd_sof_dsp_ops *ops;
344344
};
345345

346+
enum sof_hda_tream_type {
347+
SOF_HDA_AUDIO_STREAM = 0, /* normal playback/capture stream */
348+
SOF_HDA_CL_STREAM, /* code loader stream */
349+
SOF_HDA_TRACE_STREAM, /* dma trace capture stream */
350+
};
351+
346352
#define SOF_HDA_PLAYBACK_STREAMS 16
347353
#define SOF_HDA_CAPTURE_STREAMS 16
348354
#define SOF_HDA_PLAYBACK 0
@@ -442,14 +448,15 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev);
442448
int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
443449
struct hdac_ext_stream *stream,
444450
struct snd_dma_buffer *dmab,
445-
struct snd_pcm_hw_params *params);
451+
struct snd_pcm_hw_params *params,
452+
enum sof_hda_tream_type stream_type);
446453
int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
447454
struct hdac_ext_stream *stream, int cmd);
448455
irqreturn_t hda_dsp_stream_interrupt(int irq, void *context);
449456
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context);
450457
int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
451458
struct snd_dma_buffer *dmab,
452-
struct hdac_stream *stream);
459+
struct hdac_stream *stream, u32 init_offset);
453460

454461
struct hdac_ext_stream *
455462
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);

sound/soc/sof/sof-priv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ struct snd_sof_dev {
363363
struct snd_dma_buffer dmatp;
364364
int dma_trace_pages;
365365
wait_queue_head_t trace_sleep;
366-
u32 host_offset;
366+
u32 trace_init_offset; /* restore trace offset upon resume */
367+
u32 trace_offset;
367368
bool dtrace_is_enabled;
368369
bool dtrace_error;
369370

sound/soc/sof/trace.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,23 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev,
3030
loff_t pos, size_t buffer_size)
3131
{
3232
wait_queue_entry_t wait;
33+
u32 host_offset;
34+
35+
/* count the initial offset to get the buffer offset */
36+
host_offset = (sdev->trace_init_offset + sdev->trace_offset) %
37+
buffer_size;
3338

3439
/*
3540
* If host offset is less than local pos, it means write pointer of
3641
* host DMA buffer has been wrapped. We should output the trace data
3742
* at the end of host DMA buffer at first.
3843
*/
39-
if (sdev->host_offset < pos)
44+
if (host_offset < pos)
4045
return buffer_size - pos;
4146

4247
/* If there is available trace data now, it is unnecessary to wait. */
43-
if (sdev->host_offset > pos)
44-
return sdev->host_offset - pos;
48+
if (host_offset > pos)
49+
return host_offset - pos;
4550

4651
/* wait for available trace data from FW */
4752
init_waitqueue_entry(&wait, current);
@@ -58,11 +63,15 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev,
5863
remove_wait_queue(&sdev->trace_sleep, &wait);
5964

6065
out:
66+
/* update buffer offset after wait done */
67+
host_offset = (sdev->trace_init_offset + sdev->trace_offset) %
68+
buffer_size;
69+
6170
/* return bytes available for copy */
62-
if (sdev->host_offset < pos)
71+
if (host_offset < pos)
6372
return buffer_size - pos;
6473
else
65-
return sdev->host_offset - pos;
74+
return host_offset - pos;
6675
}
6776

6877
static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer,
@@ -154,15 +163,24 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev)
154163
if (sdev->dtrace_is_enabled)
155164
return -EINVAL;
156165

166+
/* update init_offset, and reinitial offset to 0 */
167+
sdev->trace_init_offset = (sdev->trace_init_offset +
168+
sdev->trace_offset) %
169+
sdev->dmatb.bytes;
170+
sdev->trace_offset = 0;
171+
157172
/* set IPC parameters */
158173
params.hdr.size = sizeof(params);
159174
params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS;
160175
params.buffer.phy_addr = sdev->dmatp.addr;
161176
params.buffer.size = sdev->dmatb.bytes;
162-
params.buffer.offset = 0;
163177
params.buffer.pages = sdev->dma_trace_pages;
164178

165-
sdev->host_offset = 0;
179+
/*
180+
* send offset to FW to require copying new logs
181+
* start from new offset if possible.
182+
*/
183+
params.buffer.offset = sdev->trace_init_offset;
166184

167185
ret = snd_sof_dma_trace_init(sdev, &params.stream_tag);
168186
if (ret < 0) {
@@ -200,6 +218,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev)
200218

201219
/* set false before start initialization */
202220
sdev->dtrace_is_enabled = false;
221+
sdev->trace_offset = 0;
222+
sdev->trace_init_offset = 0;
203223

204224
/* allocate trace page table buffer */
205225
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent,
@@ -236,6 +256,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev)
236256

237257
init_waitqueue_head(&sdev->trace_sleep);
238258

259+
init_waitqueue_head(&sdev->trace_sleep);
260+
239261
ret = snd_sof_init_trace_ipc(sdev);
240262
if (ret < 0)
241263
goto table_err;
@@ -252,8 +274,9 @@ EXPORT_SYMBOL(snd_sof_init_trace);
252274
int snd_sof_trace_update_pos(struct snd_sof_dev *sdev,
253275
struct sof_ipc_dma_trace_posn *posn)
254276
{
255-
if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) {
256-
sdev->host_offset = posn->host_offset;
277+
if (sdev->dtrace_is_enabled &&
278+
sdev->trace_offset != posn->host_offset) {
279+
sdev->trace_offset = posn->host_offset;
257280
wake_up(&sdev->trace_sleep);
258281
}
259282

0 commit comments

Comments
 (0)