Hi,

On Mon, Apr 07, 2008 at 11:52:55AM +1000, David McCullough wrote:
> 
> Jivin Wolfgang Wegner lays it down ...
> > 
> > you are right, this is a problem that could happen in theory - but on
> > the other hand there should be one and exactly one interrupt while waiting
> > for the transfer to complete, so I can not see where the other execution
> > thread triggering the second interrupt should come from.
> 
> 
> Trace and make sure it isn't.  I don't know the HW,  are you acking the
> interrupt or stopping further interrupts ?

I am just acking the interrupt, but as this driver is only capable of
I2C master anyways, there is no reason for a new interrupt to be generated
without driver intervention on the HW.

> > Well, maybe I got it wrong, but to me this looks like a busy wait,
> 
> It is,  but you aren't doing the work in your interrupt rouinte,
> and normally (ie., good practice) you would be limiting the number of
> times it can loop with a work counter or similar.  Check out some network
> dirvers for examples.

coldfire_wait_transfer is called during transfers, not in interrupt
context - so the processor would be doing busy wait almost during the
whole transfer. The driver would have to be completely re-structured
to be comparable to a network driver as far as I can see. (queueing
transfer requests and processing them in an interrupt-controlled
tasklet or something.)

> > which is clearly not what I want a 200+ MHz processor to do while
> > waiting for a slow bus like I2C.
> 
> It's only busy while there are interrupts pending on the device.  If the
> bus is slow you will easily pull everything out of the chip and exit for
> further processing before the next interrupt comes along and wakes it up.

See above - this is not true.

I agree that the possible race condition is a bit ugly and should be fixed,
but as far as I can see it is currently only a theoretical problem that can
not be triggered by current hardware.

However, as I could solve the problem by adding a second check in
coldfire_wait_transfer like this:

static int coldfire_wait_transfer(void) {

        int timeout;

        /* wait for data transfer to complete */
        timeout = wait_event_interruptible_timeout(coldfire_i2c_queue,
                                                   1 == 
atomic_read(&coldfire_i2c_irq_happened),
                                                   COLDFIRE_I2C_TIMEOUT);

        if ((timeout <= 0 ) || (*MCF_I2C_I2SR & MCF_I2C_I2SR_IAL)) {
                if((*MCF_I2C_I2SR & MCF_I2C_I2SR_ICF) && (!(*MCF_I2C_I2SR & 
MCF_I2C_I2SR_IAL))) {
                        atomic_set(&coldfire_i2c_irq_happened, 0);
                        return 0;
                }
                printk("wt: timeout = %d, I2SR = %x\n, ih = %d",timeout, 
*MCF_I2C_I2SR, atomic_read(&coldfire_i2c_irq_happened));
                return -1;
        }
        else {
                atomic_set(&coldfire_i2c_irq_happened, 0);
                return 0;
        }
};

and I can not see a timeout on I2C hardware level it is obvious to me that
the original problem is related to the waitqueue failing from time to time.

Regards,
Wolfgang

_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to