Hi!

I recently got a Sun Blade 1000.
I encountered the same problem described at
http://ubuntuforums.org/showthread.php?t=297474

The mentioned solution (removing the msleep) and switch to polling mode
is imho no good option.

Problem:
kthread kenvctrld calls wait_for_pin(), attaches itself to the
wait_queue and sets itself INTERRUPTIBLE (unneccesary because
msleep_interruptible does the same). Then it checks if the i2c-query is
already done. Usually this is not the case at first check.

Then kenvctrl calles msleep_interruptible(250). Usually 1 or 2 ms later
the i2c-bus signals by interrupt that the desired operation is done.
The interrupt-handler wakes up all tasks in the wq.
Know kenvctrld is reset to TASK_RUNNING and does about 248 ms sleeping
at kernel priority :-(


the patch attached will switch this to wait_event_interruptible_timeout.
It might be possible to change this line:

        if ((val != -ERESTARTSYS) && (val > 0))  {

to

        if (val > 0)  {

but I was not sure if I can rely on errror codes <0


Please check this patch since I do not know exactly how to proceed.


-- 
Jörg Friedrich

There are only 10 types of people:
Those who understand binary and those who don't.
--- linux-2.6.20/drivers/sbus/char/bbc_i2c.c.orig       2007-02-15 
21:26:56.000000000 +0100
+++ linux-2.6.20/drivers/sbus/char/bbc_i2c.c    2007-02-15 21:28:36.000000000 
+0100
@@ -187,19 +187,18 @@
        bp->waiting = 1;
        add_wait_queue(&bp->wq, &wait);
        while (limit-- > 0) {
-               u8 val;
+               long val;
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               *status = val = readb(bp->i2c_control_regs + 0);
-               if ((val & I2C_PCF_PIN) == 0) {
+               val = wait_event_interruptible_timeout(bp->wq,
+                       (((*status = readb(bp->i2c_control_regs + 0)) & 
I2C_PCF_PIN) == 0),
+                       msecs_to_jiffies(250));
+               if ((val != -ERESTARTSYS) && (val > 0))  {
                        ret = 0;
                        break;
                }
-               msleep_interruptible(250);
        }
        remove_wait_queue(&bp->wq, &wait);
        bp->waiting = 0;
-       current->state = TASK_RUNNING;
 
        return ret;
 }
@@ -340,7 +339,7 @@
         */
        if (bp->waiting &&
            !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
-               wake_up(&bp->wq);
+               wake_up_interruptible(&bp->wq);
 
        return IRQ_HANDLED;
 }

Reply via email to