ad1848: fix schedule while atomic, simplify MCE down code The function snd_ad1848_mce_down() called msleep() while holding a spinlock with IRQs disabled. A polling loop to check for ACI to go down was more convoluted than it needed to be. New loop should be more efficient and it a lot simpler. A polling loop to check for the device to leaving INIT mode is removed. The device must have already left init for the previous ACI loop to have finished. Signed-off-by: Trent Piepho diff -r 50502c13d2cf isa/ad1848/ad1848_lib.c --- a/isa/ad1848/ad1848_lib.c Mon Sep 17 19:08:32 2007 +0200 +++ b/isa/ad1848/ad1848_lib.c Mon Sep 17 12:57:05 2007 -0700 @@ -205,7 +205,6 @@ static void snd_ad1848_mce_down(struct s { unsigned long flags; int timeout; - unsigned long end_time; spin_lock_irqsave(&chip->reg_lock, flags); for (timeout = 5; timeout > 0; timeout--) @@ -231,39 +230,28 @@ static void snd_ad1848_mce_down(struct s return; } - /* - * Wait for (possible -- during init auto-calibration may not be set) - * calibration process to start. Needs upto 5 sample periods on AD1848 - * which at the slowest possible rate of 5.5125 kHz means 907 us. + /* + * Wait for auto-calibration (AC) process to finish, i.e. ACI to go + * low. It may take up to 5 sample periods (at most 907 us @ 5.5125 + * kHz) for the process to _start_, so it is important to wait at least + * that long before checking. Otherwise we might think AC has finished + * when it has in fact not begun. It should take 128 (no AC) or 384 + * (AC) cycles for ACI to drop. This gives a range of at most 70 ms + * with a more typical value of just under 3 ms. With a 3 ms wait, we + * will probably finish on the first loop. */ - msleep(1); - - snd_printdd("(2) jiffies = %lu\n", jiffies); - - end_time = jiffies + msecs_to_jiffies(250); - while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (time_after(jiffies, end_time)) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n"); - return; - } - msleep(1); + /* give up at ~1/4 sec at 3 ms per loop */ + for(timeout = 85; timeout > 0; timeout--) { + msleep(3); spin_lock_irqsave(&chip->reg_lock, flags); - } - - snd_printdd("(3) jiffies = %lu\n", jiffies); - - end_time = jiffies + msecs_to_jiffies(100); - while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (time_after(jiffies, end_time)) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); - return; - } - msleep(1); - spin_lock_irqsave(&chip->reg_lock, flags); - } - spin_unlock_irqrestore(&chip->reg_lock, flags); + if (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) + break; + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (!timeout) { + snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n"); + return; + } snd_printdd("(4) jiffies = %lu\n", jiffies); snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));