summaryrefslogtreecommitdiffstats
path: root/sound/drivers
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-12-21 05:42:03 -0500
committerIngo Molnar <mingo@kernel.org>2018-01-16 03:51:22 -0500
commitb03bbbe08ff04d80136b6aac152954ef308a4909 (patch)
tree00eccdb20106c5f0f4fcf4cb26cdb5ebbc51eb5c /sound/drivers
parent42f42da41b54c191ae6a775e84a86c100d66c5e8 (diff)
ALSA/dummy: Replace tasklet with softirq hrtimer
The tasklet is used to defer the execution of snd_pcm_period_elapsed() to the softirq context. Using the HRTIMER_MODE_SOFT mode invokes the timer callback in softirq context as well which renders the tasklet useless. [o-takashi: avoid stall due to a call of hrtimer_cancel() on a callback of hrtimer] Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> Reviewed-by: Takashi Iwai <tiwai@suse.de> Cc: Christoph Hellwig <hch@lst.de> Cc: Jaroslav Kysela <perex@perex.cz> Cc: John Stultz <john.stultz@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Takashi Iwai <tiwai@suse.com> Cc: Takashi Sakamoto <o-takashi@sakamocchi.jp> Cc: alsa-devel@alsa-project.org Cc: keescook@chromium.org Link: http://lkml.kernel.org/r/20171221104205.7269-35-anna-maria@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'sound/drivers')
-rw-r--r--sound/drivers/dummy.c27
1 files changed, 12 insertions, 15 deletions
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 7b2b1f766b00..6ad2ff57833d 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -375,17 +375,9 @@ struct dummy_hrtimer_pcm {
375 ktime_t period_time; 375 ktime_t period_time;
376 atomic_t running; 376 atomic_t running;
377 struct hrtimer timer; 377 struct hrtimer timer;
378 struct tasklet_struct tasklet;
379 struct snd_pcm_substream *substream; 378 struct snd_pcm_substream *substream;
380}; 379};
381 380
382static void dummy_hrtimer_pcm_elapsed(unsigned long priv)
383{
384 struct dummy_hrtimer_pcm *dpcm = (struct dummy_hrtimer_pcm *)priv;
385 if (atomic_read(&dpcm->running))
386 snd_pcm_period_elapsed(dpcm->substream);
387}
388
389static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer) 381static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)
390{ 382{
391 struct dummy_hrtimer_pcm *dpcm; 383 struct dummy_hrtimer_pcm *dpcm;
@@ -393,7 +385,14 @@ static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)
393 dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer); 385 dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer);
394 if (!atomic_read(&dpcm->running)) 386 if (!atomic_read(&dpcm->running))
395 return HRTIMER_NORESTART; 387 return HRTIMER_NORESTART;
396 tasklet_schedule(&dpcm->tasklet); 388 /*
389 * In cases of XRUN and draining, this calls .trigger to stop PCM
390 * substream.
391 */
392 snd_pcm_period_elapsed(dpcm->substream);
393 if (!atomic_read(&dpcm->running))
394 return HRTIMER_NORESTART;
395
397 hrtimer_forward_now(timer, dpcm->period_time); 396 hrtimer_forward_now(timer, dpcm->period_time);
398 return HRTIMER_RESTART; 397 return HRTIMER_RESTART;
399} 398}
@@ -403,7 +402,7 @@ static int dummy_hrtimer_start(struct snd_pcm_substream *substream)
403 struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; 402 struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
404 403
405 dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer); 404 dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer);
406 hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL); 405 hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL_SOFT);
407 atomic_set(&dpcm->running, 1); 406 atomic_set(&dpcm->running, 1);
408 return 0; 407 return 0;
409} 408}
@@ -413,14 +412,14 @@ static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
413 struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; 412 struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
414 413
415 atomic_set(&dpcm->running, 0); 414 atomic_set(&dpcm->running, 0);
416 hrtimer_cancel(&dpcm->timer); 415 if (!hrtimer_callback_running(&dpcm->timer))
416 hrtimer_cancel(&dpcm->timer);
417 return 0; 417 return 0;
418} 418}
419 419
420static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm) 420static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
421{ 421{
422 hrtimer_cancel(&dpcm->timer); 422 hrtimer_cancel(&dpcm->timer);
423 tasklet_kill(&dpcm->tasklet);
424} 423}
425 424
426static snd_pcm_uframes_t 425static snd_pcm_uframes_t
@@ -465,12 +464,10 @@ static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
465 if (!dpcm) 464 if (!dpcm)
466 return -ENOMEM; 465 return -ENOMEM;
467 substream->runtime->private_data = dpcm; 466 substream->runtime->private_data = dpcm;
468 hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 467 hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
469 dpcm->timer.function = dummy_hrtimer_callback; 468 dpcm->timer.function = dummy_hrtimer_callback;
470 dpcm->substream = substream; 469 dpcm->substream = substream;
471 atomic_set(&dpcm->running, 0); 470 atomic_set(&dpcm->running, 0);
472 tasklet_init(&dpcm->tasklet, dummy_hrtimer_pcm_elapsed,
473 (unsigned long)dpcm);
474 return 0; 471 return 0;
475} 472}
476 473