aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ctxfi/cttimer.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-06-15 08:50:52 -0400
committerTakashi Iwai <tiwai@suse.de>2009-06-15 08:52:55 -0400
commit8dca419721d188bfee5f19fad45275856c619a5c (patch)
treee953048997ccb98e3275dc0438fc02f481ad52e3 /sound/pci/ctxfi/cttimer.c
parent635c265f32d8a3f73402813d6a8dd47f2a363df5 (diff)
ALSA: ctxfi - Fix deadlock with xfi-timer
The PCM x-fi native update routine can cause deadlocks when the trigger(START) is called while the stream is running. This patch fixes the deadlock by just postponing the pcm period update to the next possible wake-up. Also it adds the flip of ti->running flag (just to be sure as now). Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ctxfi/cttimer.c')
-rw-r--r--sound/pci/ctxfi/cttimer.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index 779c6c3591a5..93b0aedc36d4 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
180 * 180 *
181 * call this inside the lock and irq disabled 181 * call this inside the lock and irq disabled
182 */ 182 */
183static int ct_xfitimer_reprogram(struct ct_timer *atimer) 183static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
184{ 184{
185 struct ct_timer_instance *ti; 185 struct ct_timer_instance *ti;
186 unsigned int min_intr = (unsigned int)-1; 186 unsigned int min_intr = (unsigned int)-1;
@@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer)
216 ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + 216 ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
217 rate - 1, rate); 217 rate - 1, rate);
218 } 218 }
219 if (ti->need_update && !can_update)
220 min_intr = 0; /* pending to the next irq */
219 if (ti->frag_count < min_intr) 221 if (ti->frag_count < min_intr)
220 min_intr = ti->frag_count; 222 min_intr = ti->frag_count;
221 } 223 }
@@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer)
235 237
236 spin_lock_irqsave(&atimer->list_lock, flags); 238 spin_lock_irqsave(&atimer->list_lock, flags);
237 list_for_each_entry(ti, &atimer->instance_head, instance_list) { 239 list_for_each_entry(ti, &atimer->instance_head, instance_list) {
238 if (ti->need_update) { 240 if (ti->running && ti->need_update) {
239 ti->need_update = 0; 241 ti->need_update = 0;
240 ti->apcm->interrupt(ti->apcm); 242 ti->apcm->interrupt(ti->apcm);
241 } 243 }
@@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
252 spin_lock_irqsave(&atimer->lock, flags); 254 spin_lock_irqsave(&atimer->lock, flags);
253 atimer->irq_handling = 1; 255 atimer->irq_handling = 1;
254 do { 256 do {
255 update = ct_xfitimer_reprogram(atimer); 257 update = ct_xfitimer_reprogram(atimer, 1);
256 spin_unlock(&atimer->lock); 258 spin_unlock(&atimer->lock);
257 if (update) 259 if (update)
258 ct_xfitimer_check_period(atimer); 260 ct_xfitimer_check_period(atimer);
@@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
265static void ct_xfitimer_prepare(struct ct_timer_instance *ti) 267static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
266{ 268{
267 ti->frag_count = ti->substream->runtime->period_size; 269 ti->frag_count = ti->substream->runtime->period_size;
270 ti->running = 0;
268 ti->need_update = 0; 271 ti->need_update = 0;
269} 272}
270 273
@@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
273static void ct_xfitimer_update(struct ct_timer *atimer) 276static void ct_xfitimer_update(struct ct_timer *atimer)
274{ 277{
275 unsigned long flags; 278 unsigned long flags;
276 int update;
277 279
278 spin_lock_irqsave(&atimer->lock, flags); 280 spin_lock_irqsave(&atimer->lock, flags);
279 if (atimer->irq_handling) { 281 if (atimer->irq_handling) {
@@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
284 } 286 }
285 287
286 ct_xfitimer_irq_stop(atimer); 288 ct_xfitimer_irq_stop(atimer);
287 update = ct_xfitimer_reprogram(atimer); 289 ct_xfitimer_reprogram(atimer, 0);
288 spin_unlock_irqrestore(&atimer->lock, flags); 290 spin_unlock_irqrestore(&atimer->lock, flags);
289 if (update)
290 ct_xfitimer_check_period(atimer);
291} 291}
292 292
293static void ct_xfitimer_start(struct ct_timer_instance *ti) 293static void ct_xfitimer_start(struct ct_timer_instance *ti)
@@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
298 spin_lock_irqsave(&atimer->lock, flags); 298 spin_lock_irqsave(&atimer->lock, flags);
299 if (list_empty(&ti->running_list)) 299 if (list_empty(&ti->running_list))
300 atimer->wc = ct_xfitimer_get_wc(atimer); 300 atimer->wc = ct_xfitimer_get_wc(atimer);
301 ti->running = 1;
302 ti->need_update = 0;
301 list_add(&ti->running_list, &atimer->running_head); 303 list_add(&ti->running_list, &atimer->running_head);
302 spin_unlock_irqrestore(&atimer->lock, flags); 304 spin_unlock_irqrestore(&atimer->lock, flags);
303 ct_xfitimer_update(atimer); 305 ct_xfitimer_update(atimer);
@@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti)
310 312
311 spin_lock_irqsave(&atimer->lock, flags); 313 spin_lock_irqsave(&atimer->lock, flags);
312 list_del_init(&ti->running_list); 314 list_del_init(&ti->running_list);
313 ti->need_update = 0; 315 ti->running = 0;
314 spin_unlock_irqrestore(&atimer->lock, flags); 316 spin_unlock_irqrestore(&atimer->lock, flags);
315 ct_xfitimer_update(atimer); 317 ct_xfitimer_update(atimer);
316} 318}