Skip to content

Commit 12c3df3

Browse files
committed
trace: dma: Fix locking and buffer wraps on DMA trace
DMA trace must be run from a work context and not from any atomic context as it waits on DMA completion IRQs. Check the host and local buffers for wrap. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent a7c6de9 commit 12c3df3

File tree

3 files changed

+72
-32
lines changed

3 files changed

+72
-32
lines changed

src/audio/dma-trace.c

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ static int dma_trace_new_buffer(struct dma_trace_data *d, uint32_t buffer_size)
6666
buffer->size = buffer_size;
6767
buffer->w_ptr = buffer->r_ptr = buffer->addr;
6868
buffer->end_addr = buffer->addr + buffer->size;
69+
buffer->avail = 0;
6970

7071
return 0;
7172
}
@@ -74,25 +75,61 @@ static void trace_send(struct dma_trace_data *d)
7475
{
7576
struct dma_trace_buf *buffer = &d->dmatb;
7677
struct dma_sg_config *config = &d->config;
77-
uint32_t size = 0;
78+
unsigned long flags;
7879
int32_t offset = 0;
79-
80-
if (buffer->w_ptr == buffer->r_ptr)
80+
uint32_t avail = buffer->avail;
81+
uint32_t bytes_copied = avail;
82+
uint32_t size;
83+
uint32_t hsize;
84+
uint32_t lsize;
85+
86+
/* any data to copy ? */
87+
if (avail == 0)
8188
return;
8289

83-
size = buffer->w_ptr - buffer->r_ptr;
84-
if (d->host_offset + size > d->host_size)
85-
d->host_offset = 0;
90+
/* copy to host in sections if we wrap */
91+
while (avail > 0) {
8692

87-
offset = dma_copy_to_host(config, d->host_offset,
88-
buffer->r_ptr, size);
89-
if (offset < 0) {
90-
trace_buffer_error("ebb");
91-
return;
93+
lsize = hsize = avail;
94+
95+
/* host buffer wrap ? */
96+
if (d->host_offset + buffer->avail > d->host_size)
97+
hsize = d->host_offset + buffer->avail - d->host_size;
98+
99+
/* local buffer wrap ? */
100+
if (buffer->r_ptr > buffer->w_ptr)
101+
lsize = buffer->end_addr - buffer->r_ptr;
102+
103+
/* get smallest size */
104+
if (hsize < lsize)
105+
size = hsize;
106+
else
107+
size = lsize;
108+
109+
/* copy this section to host */
110+
offset = dma_copy_to_host(config, d->host_offset,
111+
buffer->r_ptr, size);
112+
if (offset < 0) {
113+
trace_buffer_error("ebb");
114+
return;
115+
}
116+
117+
/* update host pointer and check for wrap */
118+
d->host_offset += size;
119+
if (d->host_offset + size >= d->host_size)
120+
d->host_offset = 0;
121+
122+
/* update local pointer and check for wrap */
123+
buffer->r_ptr += size;
124+
if (buffer->r_ptr >= buffer->end_addr)
125+
buffer->r_ptr = buffer->addr;
126+
127+
avail -= size;
92128
}
93129

94-
d->host_offset += size;
95-
buffer->r_ptr += size;
130+
spin_lock_irq(&d->lock, flags);
131+
buffer->avail -= bytes_copied;
132+
spin_unlock_irq(&d->lock, flags);
96133
}
97134

98135
static uint64_t trace_work(void *data, uint64_t delay)
@@ -125,6 +162,7 @@ int dma_trace_init(struct dma_trace_data *d)
125162
trace_data = d;
126163

127164
work_init(&d->dmat_work, trace_work, d, WORK_ASYNC);
165+
spinlock_init(&d->lock);
128166
return 0;
129167
}
130168

@@ -155,34 +193,39 @@ void dtrace_event(const char *e, uint32_t length)
155193
{
156194
struct dma_trace_buf *buffer = NULL;
157195
int margin = 0;
196+
unsigned long flags;
158197

159-
if (trace_data == NULL || length < 1)
198+
if (trace_data == NULL || length == 0)
160199
return;
161200

162201
buffer = &trace_data->dmatb;
163202
if (buffer == NULL)
164203
return;
165204

205+
spin_lock_irq(&trace_data->lock, flags);
206+
166207
margin = buffer->end_addr - buffer->w_ptr;
167208

209+
/* check for buffer wrap */
168210
if (margin > length) {
211+
212+
/* no wrap */
169213
memcpy(buffer->w_ptr, e, length);
170214
buffer->w_ptr += length;
171215
} else {
172-
memcpy(buffer->w_ptr, e, margin);
173-
buffer->w_ptr += margin;
174216

175-
if(trace_data->ready)
176-
trace_send(trace_data);
177-
178-
buffer->w_ptr = buffer->r_ptr = buffer->addr;
179-
bzero(buffer->addr, buffer->size);
217+
/* data is bigger than remaining margin so we wrap */
218+
memcpy(buffer->w_ptr, e, margin);
219+
buffer->w_ptr = buffer->addr;
180220

181221
memcpy(buffer->w_ptr, e + margin, length - margin);
182-
buffer->w_ptr += length -margin;
222+
buffer->w_ptr += length - margin;
183223
}
184224

185-
length = buffer->w_ptr - buffer->r_ptr;
186-
if (trace_data->ready && length >= (DMA_TRACE_LOCAL_SIZE / 2))
187-
trace_send(trace_data);
225+
buffer->avail += length;
226+
spin_unlock_irq(&trace_data->lock, flags);
227+
228+
/* schedule copy now if buffer > 50% full */
229+
if (trace_data->ready && buffer->avail >= (DMA_TRACE_LOCAL_SIZE / 2))
230+
work_reschedule_default(&trace_data->dmat_work, 100);
188231
}

src/include/reef/audio/dma-trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct dma_trace_buf {
4949
void *addr; /* buffer base address */
5050
void *end_addr; /* buffer end address */
5151
uint32_t size; /* size of buffer in bytes */
52+
uint32_t avail; /* avail bytes in buffer */
5253
};
5354

5455
struct dma_trace_data {
@@ -58,6 +59,7 @@ struct dma_trace_data {
5859
uint32_t host_size;
5960
struct work dmat_work;
6061
uint32_t ready;
62+
spinlock_t lock;
6163
};
6264

6365
int dma_trace_init(struct dma_trace_data *d);

src/lib/trace.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void _trace_error(uint32_t event)
6060
spin_lock_irq(&trace.lock, flags);
6161

6262
/* write timestamp and event to trace buffer */
63-
t =(volatile uint64_t*)(MAILBOX_TRACE_BASE + trace.pos);
63+
t = (volatile uint64_t*)(MAILBOX_TRACE_BASE + trace.pos);
6464
t[0] = platform_timer_get(platform_timer);
6565
t[1] = event;
6666

@@ -69,15 +69,14 @@ void _trace_error(uint32_t event)
6969

7070
trace.pos += (sizeof(uint64_t) << 1);
7171

72-
if (trace.pos >= MAILBOX_TRACE_SIZE)
72+
if (trace.pos > MAILBOX_TRACE_SIZE - sizeof(uint64_t) * 2)
7373
trace.pos = 0;
7474

7575
spin_unlock_irq(&trace.lock, flags);
7676
}
7777

7878
void _trace_event(uint32_t event)
7979
{
80-
unsigned long flags;
8180
volatile uint64_t dt[2];
8281
uint32_t et = (event & 0xff000000);
8382

@@ -87,13 +86,9 @@ void _trace_event(uint32_t event)
8786
if (et == TRACE_CLASS_DMA)
8887
return;
8988

90-
spin_lock_irq(&trace.lock, flags);
91-
9289
dt[0] = platform_timer_get(platform_timer);
9390
dt[1] = event;
9491
dtrace_event((const char*)dt, sizeof(uint64_t) * 2);
95-
96-
spin_unlock_irq(&trace.lock, flags);
9792
}
9893

9994
void trace_off(void)

0 commit comments

Comments
 (0)