Write to XMT_DATA8 register should be done after INT_STAT is cleared. So, as least one sync before XMIT_DATA8 is necessary. I will do a bit clean up.
Yes, a SSYNC_ATOMIC() macro is better for interrupt routine usage. Sonic -----Original Message----- From: Mike Frysinger [mailto:[email protected]] Sent: Friday, October 16, 2009 1:28 PM To: [email protected] Cc: [email protected] Subject: Re: [Linux-kernel-commits] [7660] trunk/drivers/i2c/busses/i2c-bfin-twi.c: Fix bug[#5275] Clear i2c int state earlier and loop till no ints left On Fri, Oct 16, 2009 at 00:11, <[email protected]> wrote: > Revision 7660 Author sonicz Date 2009-10-16 00:11:41 -0400 (Fri, 16 > Oct > 2009) > > Log Message > > Fix bug[#5275] Clear i2c int state earlier and loop till no ints left > > i2c event of next read/write byte may trigger before current int state > is cleared in the interrupt handler. So, this should be done at the > beginning of interrupt handler to avoid losing new i2c events. > > Modified: trunk/drivers/i2c/busses/i2c-bfin-twi.c (7659 => 7660) > > @@ -80,9 +80,9 @@ > {P_TWI1_SCL, P_TWI1_SDA, 0}, > }; > > -static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) > +static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, > + unsigned short twi_int_status) > { > - unsigned short twi_int_status = read_INT_STAT(iface); > unsigned short mast_stat = read_MASTER_STAT(iface); > > if (twi_int_status & XMTSERV) { > @@ -110,9 +110,6 @@ > (read_MASTER_CTL(iface) | RSTART) & ~MDIR); > } > SSYNC(); > - /* Clear status */ > - write_INT_STAT(iface, XMTSERV); > - SSYNC(); > } > if (twi_int_status & RCVSERV) { > if (iface->readNum > 0) { > @@ -145,12 +142,8 @@ > (read_MASTER_CTL(iface) | RSTART) & ~MDIR); > SSYNC(); > } > - /* Clear interrupt source */ > - write_INT_STAT(iface, RCVSERV); > - SSYNC(); > } > if (twi_int_status & MERR) { > - write_INT_STAT(iface, MERR); > write_INT_MASK(iface, 0); > write_MASTER_STAT(iface, 0x3e); > write_MASTER_CTL(iface, 0); > @@ -172,10 +165,6 @@ > * results. > */ > if (twi_int_status & MCOMP) { > - write_INT_STAT(iface, MCOMP); > - write_INT_MASK(iface, 0); > - write_MASTER_CTL(iface, 0); > - SSYNC(); > /* If it is a quick transfer, only address without data, > * not an err, return 1. > * If address is acknowledged return 1. > @@ -188,8 +177,6 @@ > return; > } > if (twi_int_status & MCOMP) { > - write_INT_STAT(iface, MCOMP); > - SSYNC(); > if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { > if (iface->readNum == 0) { > /* set the read number to 1 and ask for manual @@ -264,9 +251,18 > @@ { > struct bfin_twi_iface *iface = dev_id; > unsigned long flags; > + unsigned short twi_int_status; > > spin_lock_irqsave(&iface->lock, flags); > - bfin_twi_handle_interrupt(iface); > + while (1) { > + twi_int_status = read_INT_STAT(iface); > + if (!twi_int_status) > + break; > + /* Clear interrupt status */ > + write_INT_STAT(iface, twi_int_status); > + SSYNC(); > + bfin_twi_handle_interrupt(iface, twi_int_status); > + } > spin_unlock_irqrestore(&iface->lock, flags); > return IRQ_HANDLED; i dont think we need to ssync here. it isnt like the INT_STAT being immediately cleared has any bearing on the rest of the interrupt handling code. why not unify the ssync's here by doing: - read INT_STAT - clear INT_STAT - call bfin_twi_handle_interrupt - do ssync then pretty much all of the ssync's in bfin_twi_handle_interrupt can be dropped too since it's expected that when the func returns, a ssync will be done also, i think we should declare a SSYNC_ATOMIC() macro so that we can avoid expanding anomalies related to interrupted ssyncs. it'd make sense to use it here for example. -mike _______________________________________________ Linux-kernel-commits mailing list [email protected] https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits
