Skip to content

Commit 98f9de3

Browse files
sverdlinVinod Koul
authored and
Vinod Koul
committed
dmaengine: ep93xx: Don't drain the transfers in terminate_all()
Draining the transfers in terminate_all callback happens with IRQs disabled, therefore induces huge latency: irqsoff latency trace v1.1.5 on 4.11.0 -------------------------------------------------------------------- latency: 39770 us, #57/57, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0) ----------------- | task: process-129 (uid:0 nice:0 policy:2 rt_prio:50) ----------------- => started at: _snd_pcm_stream_lock_irqsave => ended at: snd_pcm_stream_unlock_irqrestore _------=> CPU# / _-----=> irqs-off | / _----=> need-resched || / _---=> hardirq/softirq ||| / _--=> preempt-depth |||| / delay cmd pid ||||| time | caller \ / ||||| \ | / process-129 0d.s. 3us : _snd_pcm_stream_lock_irqsave process-129 0d.s1 9us : snd_pcm_stream_lock <-_snd_pcm_stream_lock_irqsave process-129 0d.s1 15us : preempt_count_add <-snd_pcm_stream_lock process-129 0d.s2 22us : preempt_count_add <-snd_pcm_stream_lock process-129 0d.s3 32us : snd_pcm_update_hw_ptr0 <-snd_pcm_period_elapsed process-129 0d.s3 41us : soc_pcm_pointer <-snd_pcm_update_hw_ptr0 process-129 0d.s3 50us : dmaengine_pcm_pointer <-soc_pcm_pointer process-129 0d.s3 58us+: snd_dmaengine_pcm_pointer_no_residue <-dmaengine_pcm_pointer process-129 0d.s3 96us : update_audio_tstamp <-snd_pcm_update_hw_ptr0 process-129 0d.s3 103us : snd_pcm_update_state <-snd_pcm_update_hw_ptr0 process-129 0d.s3 112us : xrun <-snd_pcm_update_state process-129 0d.s3 119us : snd_pcm_stop <-xrun process-129 0d.s3 126us : snd_pcm_action <-snd_pcm_stop process-129 0d.s3 134us : snd_pcm_action_single <-snd_pcm_action process-129 0d.s3 141us : snd_pcm_pre_stop <-snd_pcm_action_single process-129 0d.s3 150us : snd_pcm_do_stop <-snd_pcm_action_single process-129 0d.s3 157us : soc_pcm_trigger <-snd_pcm_do_stop process-129 0d.s3 166us : snd_dmaengine_pcm_trigger <-soc_pcm_trigger process-129 0d.s3 175us : ep93xx_dma_terminate_all <-snd_dmaengine_pcm_trigger process-129 0d.s3 182us : preempt_count_add <-ep93xx_dma_terminate_all process-129 0d.s4 189us*: m2p_hw_shutdown <-ep93xx_dma_terminate_all process-129 0d.s4 39472us : m2p_hw_setup <-ep93xx_dma_terminate_all ... rest skipped... process-129 0d.s. 40080us : <stack trace> => ep93xx_dma_tasklet => tasklet_action => __do_softirq => irq_exit => __handle_domain_irq => vic_handle_irq => __irq_usr => 0xb66c6668 Just abort the transfers and warn if the HW state is not what we expect. Move draining into device_synchronize callback. Signed-off-by: Alexander Sverdlin <[email protected]> Cc: [email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 0037ae4 commit 98f9de3

File tree

1 file changed

+33
-4
lines changed

1 file changed

+33
-4
lines changed

drivers/dma/ep93xx_dma.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ struct ep93xx_dma_engine {
201201
struct dma_device dma_dev;
202202
bool m2m;
203203
int (*hw_setup)(struct ep93xx_dma_chan *);
204+
void (*hw_synchronize)(struct ep93xx_dma_chan *);
204205
void (*hw_shutdown)(struct ep93xx_dma_chan *);
205206
void (*hw_submit)(struct ep93xx_dma_chan *);
206207
int (*hw_interrupt)(struct ep93xx_dma_chan *);
@@ -333,21 +334,27 @@ static inline u32 m2p_channel_state(struct ep93xx_dma_chan *edmac)
333334
return (readl(edmac->regs + M2P_STATUS) >> 4) & 0x3;
334335
}
335336

336-
static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
337+
static void m2p_hw_synchronize(struct ep93xx_dma_chan *edmac)
337338
{
339+
unsigned long flags;
338340
u32 control;
339341

342+
spin_lock_irqsave(&edmac->lock, flags);
340343
control = readl(edmac->regs + M2P_CONTROL);
341344
control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
342345
m2p_set_control(edmac, control);
346+
spin_unlock_irqrestore(&edmac->lock, flags);
343347

344348
while (m2p_channel_state(edmac) >= M2P_STATE_ON)
345-
cpu_relax();
349+
schedule();
350+
}
346351

352+
static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
353+
{
347354
m2p_set_control(edmac, 0);
348355

349-
while (m2p_channel_state(edmac) == M2P_STATE_STALL)
350-
cpu_relax();
356+
while (m2p_channel_state(edmac) != M2P_STATE_IDLE)
357+
dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n");
351358
}
352359

353360
static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
@@ -1162,6 +1169,26 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
11621169
return NULL;
11631170
}
11641171

1172+
/**
1173+
* ep93xx_dma_synchronize - Synchronizes the termination of transfers to the
1174+
* current context.
1175+
* @chan: channel
1176+
*
1177+
* Synchronizes the DMA channel termination to the current context. When this
1178+
* function returns it is guaranteed that all transfers for previously issued
1179+
* descriptors have stopped and and it is safe to free the memory associated
1180+
* with them. Furthermore it is guaranteed that all complete callback functions
1181+
* for a previously submitted descriptor have finished running and it is safe to
1182+
* free resources accessed from within the complete callbacks.
1183+
*/
1184+
static void ep93xx_dma_synchronize(struct dma_chan *chan)
1185+
{
1186+
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
1187+
1188+
if (edmac->edma->hw_synchronize)
1189+
edmac->edma->hw_synchronize(edmac);
1190+
}
1191+
11651192
/**
11661193
* ep93xx_dma_terminate_all - terminate all transactions
11671194
* @chan: channel
@@ -1325,6 +1352,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
13251352
dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg;
13261353
dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic;
13271354
dma_dev->device_config = ep93xx_dma_slave_config;
1355+
dma_dev->device_synchronize = ep93xx_dma_synchronize;
13281356
dma_dev->device_terminate_all = ep93xx_dma_terminate_all;
13291357
dma_dev->device_issue_pending = ep93xx_dma_issue_pending;
13301358
dma_dev->device_tx_status = ep93xx_dma_tx_status;
@@ -1342,6 +1370,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
13421370
} else {
13431371
dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
13441372

1373+
edma->hw_synchronize = m2p_hw_synchronize;
13451374
edma->hw_setup = m2p_hw_setup;
13461375
edma->hw_shutdown = m2p_hw_shutdown;
13471376
edma->hw_submit = m2p_hw_submit;

0 commit comments

Comments
 (0)