linux-mtd digest, Vol 1 #756 - 2 msgs
Alessandro Bolgia
alessandro.bolgia at st.com
Tue Jan 21 07:14:33 EST 2003
linux-mtd-request at lists.infradead.org wrote:
> Send linux-mtd mailing list submissions to
> linux-mtd at lists.infradead.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
> http://lists.infradead.org/mailman/listinfo/linux-mtd
> or, via email, send a message with subject or body 'help' to
> linux-mtd-request at lists.infradead.org
>
> You can reach the person managing the list at
> linux-mtd-admin at lists.infradead.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of linux-mtd digest..."
>
> Today's Topics:
>
> 1. Re: About flash chip writing/erasing, reading chip status. (Steve Wahl)
> 2. Re: About flash chip writing/erasing, reading chip status. (Darren Freeman)
>
> --__--__--
>
> Message: 1
> Date: Mon, 20 Jan 2003 11:28:10 -0600
> From: Steve Wahl <swahl at brecis.com>
> To: Linux MTD mailing list <linux-mtd at lists.infradead.org>
> Subject: Re: About flash chip writing/erasing, reading chip status.
>
> Dear MTD folk,
>
> Hmm. 5 days and no replies. That seems unusual for this list. Or am
> I confusing it with the jffs2 developers list?
>
> I don't want to be a pest. But I did expect to see some kind of
> interest...
>
> * Was I to wordy?
>
> * Did I send to the wrong place?
>
> * Is there a low-level chip "expert" who happens to be away from
> email, who usually replies to stuff like this?
>
> I want to be a good member of the commuity. I'd love to make the code
> we ship match CVS 100% for ease of future maintenance. And I'd love
> to save someone else the trouble of finding this minor "bug".
>
> How can I do better at this?
>
> --> Steve Wahl, Brecis Communications
>
> On Wed, Jan 15, 2003 at 11:37:05AM -0600, Steve Wahl wrote:
> > I'm trying to place MTD and JFFS2 on our board, and I'm getting
> > occasional messages like "Warning: DQ5 raised while erase operation
> > was in progress, but erase completed OK" messages.
> >
> > I think the general method for polling the status of the chips is just
> > a bit wrong, or in other words, this warning is NORMAL operation and
> > should not be printed.
> >
> > If I understand things correctly, you start an operation like erasing
> > a block, then you get the status by performing a read to that block.
> > If the operation is in progress, data bit 6 toggles, and data bit 5
> > stays 0. If the operation succeeds, data bits 6 and 5 return the data
> > at that address (bit 6 stops toggling). If the operation fails, bit 6
> > keeps toggling and bit 5 goes to 1.
> >
> > The general algorithm used in mtd (recent CVS, cfi_cmdset_0002.c,v
> > 1.61 2002/11/17 13:10:34 spse) goes something like this (timeout
> > condition left out of the loop for brevity)
> >
> > ------------------------------------------------------------
> > /* oldstatus and status are two reads from the same address */
> > /* in each place it occurs in this code */
> >
> > read oldstatus;
> > read status;
> >
> > while ( ((status & bit6) != (oldstatus & bit6))
> > && ((status & bit5) == 0) )
> > {
> > read oldstatus;
> > read status;
> > }
> >
> > if ( (status & bit6) != (oldstatus & bit6) )
> > {
> > /* still toggling, but exited loop. Why? */
> >
> > if ( status & bit5 != 0 )
> > {
> > /* bit5 went high. */
> > /* are we still toggling? */
> > read oldstatus;
> > read status;
> >
> > if (status == oldstatus)
> > {
> > /* no longer toggling, operation done */
> > printk("Warning: DQ5 raised while ...") ;
> > }
> > else
> > {
> > /* DQ5 went active, reset the chip */
> > ...
> > }
> > }
> >
> > }
> > ------------------------------------------------------------
> >
> > [ In the real code, there are some extra reads in the while loop that
> > make the condition I'm about to describe less likely, but it can still
> > happen. ]
> >
> > Let's say we're looking at an erase operation (the one I seem to run
> > into). Say we manage to just get lucky, and within the while loop,
> > the read of oldstatus returns the last status register value, and
> > status gets the actual data because the chip has returned to read
> > mode. Status's value will be 0xFF, the erased value. Furthermore,
> > suppose we get lucky and the toggle bit's value in the read of
> > oldstatus was a '0' (so in binary, oldstatus would have been
> > 'x00x-xxxx'). So the toggle bit is seen as still toggling in the
> > while loop, but bit5 suddenly goes from 0 to 1.
> >
> > This will end up printing the warning message erroneously.
> >
> > I think the "correct" thing to do would be to examine bit 5 from
> > oldstatus, so you're only looking at bit 5 from an earlier read, where
> > you know bit 6 has since toggled. Like this:
> >
> > read oldstatus;
> > read status;
> >
> > while ( ((status & bit6) != (oldstatus & bit6))
> > && ((oldstatus & bit5) == 0) )
> > {
> > read oldstatus;
> > read status;
> > }
> >
> > if ( (status & bit6) != (oldstatus & bit6) )
> > {
> > /* still toggling, but exited loop. Why? */
> >
> > if ( oldstatus & bit5 != 0 )
> > {
> > /* bit5 went high. */
> > /* NOTE: NO NEED TO CHECK IF WE'RE STILL TOGGLING. */
> > /* we know we are, because we checked bit5 in the */
> > /* previous read, and a read after it had bit6 */
> > /* different. */
> > /* DQ5 went active, reset the chip */
> > ...
> > }
> >
> > }
> >
> > I also think there's another error in the original code. The original
> > code sets
> >
> > dq5 = CMD(1<<5);
> >
> > which, if I understand things, sets up a word the correct width, with
> > a bit in EACH bit 5 position if you have interleaved chips. Yet the
> > check for bit 5 being set (not being set in this case) is stated as
> >
> > ((status & dq5) != dq5)
> >
> > which will only trigger when ALL bit5's are set. I think it should
> > instead be
> >
> > ((status & dq5) == 0)
> >
> > which triggers when ANY bit5 gets set. Similarly, tests for
> >
> > ((status & dq5) == dq5)
> >
> > should instead be
> >
> > ((status & dq5) != 0)
> >
> > I've attached a patch file that changes both these things. Please let
> > me know what you think.
> >
> > --> Steve Wahl, Brecis Communications.
> >
> >
>
> > --- cfi_cmdset_0002.c.orig Wed Jan 15 11:13:11 2003
> > +++ cfi_cmdset_0002.c Wed Jan 15 11:25:29 2003
> > @@ -520,7 +520,7 @@
> > status = cfi_read(map, adr);
> >
> > while( (status & dq6) != (oldstatus & dq6) &&
> > - (status & dq5) != dq5 &&
> > + (oldstatus & dq5) == 0 &&
> > !time_after(jiffies, timeo) ) {
> >
> > if (need_resched()) {
> > @@ -536,20 +536,17 @@
> >
> > if( (status & dq6) != (oldstatus & dq6) ) {
> > /* The erasing didn't stop?? */
> > - if( (status & dq5) == dq5 ) {
> > - /* When DQ5 raises, we must check once again
> > - if DQ6 is toggling. If not, the erase has been
> > - completed OK. If not, reset chip. */
> > - oldstatus = cfi_read(map, adr);
> > - status = cfi_read(map, adr);
> > -
> > - if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
> > - printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
> > - } else {
> > - /* DQ5 is active so we can do a reset and stop the erase */
> > - cfi_write(map, CMD(0xF0), chip->start);
> > - printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
> > - }
> > + if( (status & dq5) != 0 ) {
> > +
> > + /* one or more bit5's set. */
> > +
> > + /* no need to re-check if bit 6 is toggling, as */
> > + /* we've already seen bit 6 toggle after bit 5 */
> > + /* was set. */
> > +
> > + /* DQ5 is active so we can do a reset and stop the erase */
> > + cfi_write(map, CMD(0xF0), chip->start);
> > + printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
> > } else {
> > printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");
> >
> > @@ -773,7 +770,7 @@
> > oldstatus = cfi_read(map, adr);
> > status = cfi_read(map, adr);
> > while( ((status & dq6) != (oldstatus & dq6)) &&
> > - ((status & dq5) != dq5) &&
> > + ((oldstatus & dq5) == 0) &&
> > !time_after(jiffies, timeo)) {
> > int wait_reps;
> >
> > @@ -805,7 +802,7 @@
> > for(wait_reps = 0;
> > (wait_reps < 100) &&
> > ((status & dq6) != (oldstatus & dq6)) &&
> > - ((status & dq5) != dq5);
> > + ((oldstatus & dq5) == 0);
> > wait_reps++) {
> >
> > /* Latency issues. Drop the lock, wait a while and retry */
> > @@ -822,7 +819,7 @@
> > }
> > if ((status & dq6) != (oldstatus & dq6)) {
> > /* The erasing didn't stop?? */
> > - if ((status & dq5) == dq5) {
> > + if ((oldstatus & dq5) != 0) {
> > /* dq5 is active so we can do a reset and stop the erase */
> > cfi_write(map, CMD(0xF0), chip->start);
> > }
> > @@ -897,7 +894,7 @@
> > oldstatus = cfi_read(map, adr);
> > status = cfi_read(map, adr);
> > while( ((status & dq6) != (oldstatus & dq6)) &&
> > - ((status & dq5) != dq5) &&
> > + ((oldstatus & dq5) == 0) &&
> > !time_after(jiffies, timeo)) {
> > int wait_reps;
> >
> > @@ -929,7 +926,7 @@
> > for(wait_reps = 0;
> > (wait_reps < 100) &&
> > ((status & dq6) != (oldstatus & dq6)) &&
> > - ((status & dq5) != dq5);
> > + ((oldstatus & dq5) == 0);
> > wait_reps++) {
> >
> > /* Latency issues. Drop the lock, wait a while and retry */
> > @@ -947,34 +944,28 @@
> > if( (status & dq6) != (oldstatus & dq6) )
> > {
> > /* The erasing didn't stop?? */
> > - if( ( status & dq5 ) == dq5 )
> > + if( ( oldstatus & dq5 ) != 0 )
> > {
> > - /* When DQ5 raises, we must check once again if DQ6 is toggling.
> > - If not, the erase has been completed OK. If not, reset chip. */
> > - oldstatus = cfi_read( map, adr );
> > - status = cfi_read( map, adr );
> > -
> > - if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) )
> > - {
> > - printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" );
> > - }
> > - else
> > - {
> > - /* DQ5 is active so we can do a reset and stop the erase */
> > - cfi_write(map, CMD(0xF0), chip->start);
> > - printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
> > - }
> > + /* one or more bit5's set. */
> > +
> > + /* no need to re-check if bit 6 is toggling, as */
> > + /* we've already seen bit 6 toggle after bit 5 */
> > + /* was set. */
> > +
> > + /* DQ5 is active so we can do a reset and stop the erase */
> > + cfi_write(map, CMD(0xF0), chip->start);
> > + printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
> > }
> > - else
> > - {
> > - printk( "Waiting for erase to complete timed out in do_erase_oneblock.");
> > + else
> > + {
> > + printk( "Waiting for erase to complete timed out in do_erase_oneblock.");
> >
> > - chip->state = FL_READY;
> > - wake_up(&chip->wq);
> > - cfi_spin_unlock(chip->mutex);
> > - DISABLE_VPP(map);
> > - return -EIO;
> > - }
> > + chip->state = FL_READY;
> > + wake_up(&chip->wq);
> > + cfi_spin_unlock(chip->mutex);
> > + DISABLE_VPP(map);
> > + return -EIO;
> > + }
> > }
> >
> > DISABLE_VPP(map);
>
> --__--__--
>
> Message: 2
> Subject: Re: About flash chip writing/erasing, reading chip status.
> From: Darren Freeman <free0076 at infoeng.flinders.edu.au>
> Reply-To: dfreeman at ieee.org
> To: Steve Wahl <swahl at brecis.com>
> Cc: Linux MTD List <linux-mtd at lists.infradead.org>
> Organization:
> Date: 21 Jan 2003 05:31:27 +1030
>
> On Tue, 2003-01-21 at 03:58, Steve Wahl wrote:
> > Dear MTD folk,
> >
> > Hmm. 5 days and no replies. That seems unusual for this list. Or am
> > I confusing it with the jffs2 developers list?
>
> > How can I do better at this?
>
> Keep waiting ;)
>
> > --> Steve Wahl, Brecis Communications
>
> Have fun,
> Darren
>
> --__--__--
>
> ______________________________________________________
> Linux MTD discussion mailing list digest
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
> End of linux-mtd Digest
More information about the linux-mtd
mailing list