Commit ed14d9ae authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/timer-fixes' into for-next

Pull the fixes for possible races in the resolution callback.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 7c1543f6 9d4d207d
...@@ -371,9 +371,7 @@ static int initialize_timer(struct snd_seq_timer *tmr) ...@@ -371,9 +371,7 @@ static int initialize_timer(struct snd_seq_timer *tmr)
tmr->ticks = 1; tmr->ticks = 1;
if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
unsigned long r = t->hw.resolution; unsigned long r = snd_timer_resolution(tmr->timeri);
if (! r && t->hw.c_resolution)
r = t->hw.c_resolution(t);
if (r) { if (r) {
tmr->ticks = (unsigned int)(1000000000uL / (r * freq)); tmr->ticks = (unsigned int)(1000000000uL / (r * freq));
if (! tmr->ticks) if (! tmr->ticks)
......
...@@ -427,25 +427,35 @@ int snd_timer_close(struct snd_timer_instance *timeri) ...@@ -427,25 +427,35 @@ int snd_timer_close(struct snd_timer_instance *timeri)
} }
EXPORT_SYMBOL(snd_timer_close); EXPORT_SYMBOL(snd_timer_close);
static unsigned long snd_timer_hw_resolution(struct snd_timer *timer)
{
if (timer->hw.c_resolution)
return timer->hw.c_resolution(timer);
else
return timer->hw.resolution;
}
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{ {
struct snd_timer * timer; struct snd_timer * timer;
unsigned long ret = 0;
unsigned long flags;
if (timeri == NULL) if (timeri == NULL)
return 0; return 0;
timer = timeri->timer; timer = timeri->timer;
if (timer) { if (timer) {
if (timer->hw.c_resolution) spin_lock_irqsave(&timer->lock, flags);
return timer->hw.c_resolution(timer); ret = snd_timer_hw_resolution(timer);
return timer->hw.resolution; spin_unlock_irqrestore(&timer->lock, flags);
} }
return 0; return ret;
} }
EXPORT_SYMBOL(snd_timer_resolution); EXPORT_SYMBOL(snd_timer_resolution);
static void snd_timer_notify1(struct snd_timer_instance *ti, int event) static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
{ {
struct snd_timer *timer; struct snd_timer *timer = ti->timer;
unsigned long resolution = 0; unsigned long resolution = 0;
struct snd_timer_instance *ts; struct snd_timer_instance *ts;
struct timespec tstamp; struct timespec tstamp;
...@@ -457,14 +467,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) ...@@ -457,14 +467,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
event > SNDRV_TIMER_EVENT_PAUSE)) event > SNDRV_TIMER_EVENT_PAUSE))
return; return;
if (event == SNDRV_TIMER_EVENT_START || if (timer &&
event == SNDRV_TIMER_EVENT_CONTINUE) (event == SNDRV_TIMER_EVENT_START ||
resolution = snd_timer_resolution(ti); event == SNDRV_TIMER_EVENT_CONTINUE))
resolution = snd_timer_hw_resolution(timer);
if (ti->ccallback) if (ti->ccallback)
ti->ccallback(ti, event, &tstamp, resolution); ti->ccallback(ti, event, &tstamp, resolution);
if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
return; return;
timer = ti->timer;
if (timer == NULL) if (timer == NULL)
return; return;
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
...@@ -592,7 +602,7 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) ...@@ -592,7 +602,7 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
else else
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED; timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_CONTINUE); SNDRV_TIMER_EVENT_PAUSE);
unlock: unlock:
spin_unlock_irqrestore(&timer->lock, flags); spin_unlock_irqrestore(&timer->lock, flags);
return result; return result;
...@@ -614,7 +624,7 @@ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) ...@@ -614,7 +624,7 @@ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
list_del_init(&timeri->ack_list); list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list); list_del_init(&timeri->active_list);
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_CONTINUE); SNDRV_TIMER_EVENT_PAUSE);
spin_unlock(&timeri->timer->lock); spin_unlock(&timeri->timer->lock);
} }
spin_unlock_irqrestore(&slave_active_lock, flags); spin_unlock_irqrestore(&slave_active_lock, flags);
...@@ -771,10 +781,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ...@@ -771,10 +781,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
spin_lock_irqsave(&timer->lock, flags); spin_lock_irqsave(&timer->lock, flags);
/* remember the current resolution */ /* remember the current resolution */
if (timer->hw.c_resolution) resolution = snd_timer_hw_resolution(timer);
resolution = timer->hw.c_resolution(timer);
else
resolution = timer->hw.resolution;
/* loop for all active instances /* loop for all active instances
* Here we cannot use list_for_each_entry because the active_list of a * Here we cannot use list_for_each_entry because the active_list of a
...@@ -1014,12 +1021,8 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam ...@@ -1014,12 +1021,8 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
spin_lock_irqsave(&timer->lock, flags); spin_lock_irqsave(&timer->lock, flags);
if (event == SNDRV_TIMER_EVENT_MSTART || if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE || event == SNDRV_TIMER_EVENT_MCONTINUE ||
event == SNDRV_TIMER_EVENT_MRESUME) { event == SNDRV_TIMER_EVENT_MRESUME)
if (timer->hw.c_resolution) resolution = snd_timer_hw_resolution(timer);
resolution = timer->hw.c_resolution(timer);
else
resolution = timer->hw.resolution;
}
list_for_each_entry(ti, &timer->active_list_head, active_list) { list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->ccallback) if (ti->ccallback)
ti->ccallback(ti, event, tstamp, resolution); ti->ccallback(ti, event, tstamp, resolution);
...@@ -1656,10 +1659,8 @@ static int snd_timer_user_gstatus(struct file *file, ...@@ -1656,10 +1659,8 @@ static int snd_timer_user_gstatus(struct file *file,
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
t = snd_timer_find(&tid); t = snd_timer_find(&tid);
if (t != NULL) { if (t != NULL) {
if (t->hw.c_resolution) spin_lock_irq(&t->lock);
gstatus.resolution = t->hw.c_resolution(t); gstatus.resolution = snd_timer_hw_resolution(t);
else
gstatus.resolution = t->hw.resolution;
if (t->hw.precise_resolution) { if (t->hw.precise_resolution) {
t->hw.precise_resolution(t, &gstatus.resolution_num, t->hw.precise_resolution(t, &gstatus.resolution_num,
&gstatus.resolution_den); &gstatus.resolution_den);
...@@ -1667,6 +1668,7 @@ static int snd_timer_user_gstatus(struct file *file, ...@@ -1667,6 +1668,7 @@ static int snd_timer_user_gstatus(struct file *file,
gstatus.resolution_num = gstatus.resolution; gstatus.resolution_num = gstatus.resolution;
gstatus.resolution_den = 1000000000uL; gstatus.resolution_den = 1000000000uL;
} }
spin_unlock_irq(&t->lock);
} else { } else {
err = -ENODEV; err = -ENODEV;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment