Merge branch 'topic/timer-fixes' into for-next
Pull yet another ALSA core timer fixes and cleanups. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
commit
3a23fd0415
|
@ -43,7 +43,6 @@
|
|||
#define SNDRV_TIMER_IFLG_START 0x00000004
|
||||
#define SNDRV_TIMER_IFLG_AUTO 0x00000008 /* auto restart */
|
||||
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use tasklet) */
|
||||
#define SNDRV_TIMER_IFLG_CALLBACK 0x00000020 /* timer callback is active */
|
||||
#define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040 /* exclusive owner - no more instances */
|
||||
#define SNDRV_TIMER_IFLG_EARLY_EVENT 0x00000080 /* write early event to the poll queue */
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
/* internal flags */
|
||||
#define SNDRV_TIMER_IFLG_PAUSED 0x00010000
|
||||
#define SNDRV_TIMER_IFLG_DEAD 0x00020000
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_HRTIMER)
|
||||
#define DEFAULT_TIMER_LIMIT 4
|
||||
|
@ -353,20 +354,25 @@ EXPORT_SYMBOL(snd_timer_open);
|
|||
*/
|
||||
static int snd_timer_close_locked(struct snd_timer_instance *timeri)
|
||||
{
|
||||
struct snd_timer *timer = NULL;
|
||||
struct snd_timer *timer = timeri->timer;
|
||||
struct snd_timer_instance *slave, *tmp;
|
||||
|
||||
if (timer) {
|
||||
spin_lock_irq(&timer->lock);
|
||||
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
|
||||
spin_unlock_irq(&timer->lock);
|
||||
}
|
||||
|
||||
list_del(&timeri->open_list);
|
||||
|
||||
/* force to stop the timer */
|
||||
snd_timer_stop(timeri);
|
||||
|
||||
timer = timeri->timer;
|
||||
if (timer) {
|
||||
timer->num_instances--;
|
||||
/* wait, until the active callback is finished */
|
||||
spin_lock_irq(&timer->lock);
|
||||
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
|
||||
while (!list_empty(&timeri->ack_list)) {
|
||||
spin_unlock_irq(&timer->lock);
|
||||
udelay(10);
|
||||
spin_lock_irq(&timer->lock);
|
||||
|
@ -497,6 +503,10 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&timer->lock, flags);
|
||||
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
|
||||
result = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
if (timer->card && timer->card->shutdown) {
|
||||
result = -ENODEV;
|
||||
goto unlock;
|
||||
|
@ -541,11 +551,16 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
|
|||
bool start)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
spin_lock_irqsave(&slave_active_lock, flags);
|
||||
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
|
||||
spin_unlock_irqrestore(&slave_active_lock, flags);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
|
||||
if (timeri->master && timeri->timer) {
|
||||
|
@ -556,8 +571,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
|
|||
SNDRV_TIMER_EVENT_CONTINUE);
|
||||
spin_unlock(&timeri->timer->lock);
|
||||
}
|
||||
err = 1; /* delayed start */
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&slave_active_lock, flags);
|
||||
return 1; /* delayed start */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* stop/pause a master timer */
|
||||
|
@ -720,6 +737,45 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
|
|||
timer->sticks = ticks;
|
||||
}
|
||||
|
||||
/* call callbacks in timer ack list */
|
||||
static void snd_timer_process_callbacks(struct snd_timer *timer,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct snd_timer_instance *ti;
|
||||
unsigned long resolution, ticks;
|
||||
|
||||
while (!list_empty(head)) {
|
||||
ti = list_first_entry(head, struct snd_timer_instance,
|
||||
ack_list);
|
||||
|
||||
if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
|
||||
ticks = ti->pticks;
|
||||
ti->pticks = 0;
|
||||
resolution = ti->resolution;
|
||||
|
||||
spin_unlock(&timer->lock);
|
||||
if (ti->callback)
|
||||
ti->callback(ti, resolution, ticks);
|
||||
spin_lock(&timer->lock);
|
||||
}
|
||||
|
||||
/* remove from ack_list and make empty */
|
||||
list_del_init(&ti->ack_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* clear pending instances from ack list */
|
||||
static void snd_timer_clear_callbacks(struct snd_timer *timer,
|
||||
struct list_head *head)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&timer->lock, flags);
|
||||
while (!list_empty(head))
|
||||
list_del_init(head->next);
|
||||
spin_unlock_irqrestore(&timer->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* timer tasklet
|
||||
*
|
||||
|
@ -727,34 +783,15 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
|
|||
static void snd_timer_tasklet(unsigned long arg)
|
||||
{
|
||||
struct snd_timer *timer = (struct snd_timer *) arg;
|
||||
struct snd_timer_instance *ti;
|
||||
struct list_head *p;
|
||||
unsigned long resolution, ticks;
|
||||
unsigned long flags;
|
||||
|
||||
if (timer->card && timer->card->shutdown)
|
||||
if (timer->card && timer->card->shutdown) {
|
||||
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&timer->lock, flags);
|
||||
/* now process all callbacks */
|
||||
while (!list_empty(&timer->sack_list_head)) {
|
||||
p = timer->sack_list_head.next; /* get first item */
|
||||
ti = list_entry(p, struct snd_timer_instance, ack_list);
|
||||
|
||||
/* remove from ack_list and make empty */
|
||||
list_del_init(p);
|
||||
|
||||
ticks = ti->pticks;
|
||||
ti->pticks = 0;
|
||||
resolution = ti->resolution;
|
||||
|
||||
ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
|
||||
spin_unlock(&timer->lock);
|
||||
if (ti->callback)
|
||||
ti->callback(ti, resolution, ticks);
|
||||
spin_lock(&timer->lock);
|
||||
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
|
||||
}
|
||||
snd_timer_process_callbacks(timer, &timer->sack_list_head);
|
||||
spin_unlock_irqrestore(&timer->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -767,16 +804,18 @@ static void snd_timer_tasklet(unsigned long arg)
|
|||
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
||||
{
|
||||
struct snd_timer_instance *ti, *ts, *tmp;
|
||||
unsigned long resolution, ticks;
|
||||
struct list_head *p, *ack_list_head;
|
||||
unsigned long resolution;
|
||||
struct list_head *ack_list_head;
|
||||
unsigned long flags;
|
||||
int use_tasklet = 0;
|
||||
|
||||
if (timer == NULL)
|
||||
return;
|
||||
|
||||
if (timer->card && timer->card->shutdown)
|
||||
if (timer->card && timer->card->shutdown) {
|
||||
snd_timer_clear_callbacks(timer, &timer->ack_list_head);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&timer->lock, flags);
|
||||
|
||||
|
@ -790,6 +829,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
*/
|
||||
list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
|
||||
active_list) {
|
||||
if (ti->flags & SNDRV_TIMER_IFLG_DEAD)
|
||||
continue;
|
||||
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
|
||||
continue;
|
||||
ti->pticks += ticks_left;
|
||||
|
@ -839,23 +880,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
|
|||
}
|
||||
|
||||
/* now process all fast callbacks */
|
||||
while (!list_empty(&timer->ack_list_head)) {
|
||||
p = timer->ack_list_head.next; /* get first item */
|
||||
ti = list_entry(p, struct snd_timer_instance, ack_list);
|
||||
|
||||
/* remove from ack_list and make empty */
|
||||
list_del_init(p);
|
||||
|
||||
ticks = ti->pticks;
|
||||
ti->pticks = 0;
|
||||
|
||||
ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
|
||||
spin_unlock(&timer->lock);
|
||||
if (ti->callback)
|
||||
ti->callback(ti, resolution, ticks);
|
||||
spin_lock(&timer->lock);
|
||||
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
|
||||
}
|
||||
snd_timer_process_callbacks(timer, &timer->ack_list_head);
|
||||
|
||||
/* do we have any slow callbacks? */
|
||||
use_tasklet = !list_empty(&timer->sack_list_head);
|
||||
|
|
Loading…
Reference in New Issue