Numonyx NOR and chip->mutex bug?
Joakim Tjernlund
joakim.tjernlund at transmode.se
Thu Feb 24 05:50:21 EST 2011
Anders Grafström <grfstrm at users.sourceforge.net> wrote on 2011/02/10 14:21:36:
>
> On 2011-02-09 22:59, Michael Cashwell wrote:
> > On Feb 9, 2011, at 3:13 PM, Joakim Tjernlund wrote:
> >
> >> hmm, this sounds similar(from http://www.numonyx.com/Documents/Specification%20Updates/SU-309045_P30.pdf)
> >>
> >> 5. W602: erase suspend resume operation
> >> Problem: P30 product may fail to erase in intensive erase/suspend/resume environments. This is
> >> due to an internal firmware issue that is exhibited in certain applications that require at
> >> least 3000 to 4000 erase/suspend/resume cycles during the erase of a single block.
> >> Implication: Customer may see erase failure (SR reports “A0”) during a background erase. This
> >> does not damage the device in any way, but data in the block may be disturbed from its
> >> original state.
>
> I've seen this issue with Intel 28F640J5 chips as well.
>
> There's an old thread on it.
> http://lists.infradead.org/pipermail/linux-mtd/2008-April/021266.html
>
> A delay was suggested similar to the one you're experimenting with I think.
> http://lists.infradead.org/pipermail/linux-mtd/2008-April/021436.html
Been a while but it just occurred to me that you might see something similar as
Michael.
This program of yours:
static void erase_suspend(unsigned int loops)
{
volatile unsigned int *flash = (unsigned int *)0x41040000;
unsigned int i;
unsigned int suspends = 0;
unsigned int words = 2;
unsigned int timeout;
/* Make sure there's something to erase */
for (i = 0; i < 0x10000; i++) {
if (flash[i] == 0xffffffff) {
flash[i] = 0x00400040;
flash[i] = 0;
while ((flash[i] & 0x00800080) != 0x00800080);
}
}
/* Clear status */
flash[0] = 0x00500050;
/* Erase */
flash[0] = 0x00200020;
flash[0] = 0x00d000d0;
while (1) {
/* Suspend */
flash[0] = 0x00b000b0;
flash[0] = 0x00700070;
timeout = 100000;
while ((flash[0] & 0x00800080) != 0x00800080 && --timeout);
if (!timeout)
printf("suspend timeout\n");
suspends++;
/* Short delay */
for (i = 0; i < 1000; i++);
/* Resume */
flash[0] = 0x00d000d0;
flash[0] = 0x00700070;
/* Erase done ? */
if ((flash[0] & 0x00800080) == 0x00800080) {
printf("\nstatus %08x\n", flash[0]);
break;
}
/* Short delay */
for (i = 0; i < loops; i++);
}
/* Read array */
flash[0] = 0x00ff00ff;
/* Show the first 2 failed words */
for (i = 0; i < 0x10000; i++) {
if (flash[i] != 0xffffffff) {
printf("%08x\n", flash[i]);
if (--words == 0)
break;
}
}
printf("%d suspends\n", suspends);
}
void test_flash_erase_suspend(void)
{
unsigned int loops;
for (loops = 6000; loops > 2000; loops -= 500) {
printf("\n%d loops", loops);
erase_suspend(loops);
}
}
It produced this output at one occasion:
6000 loops
status 00800080
ffff0000
ffff0000
4783 suspends
---------------------
See the status 00800080 ?
Looking at the code this should not be possible, right?
looking closer though it becomes clearer:
if ((flash[0] & 0x00800080) == 0x00800080) {
printf("\nstatus %08x\n", flash[0]);
break;
}
There are two status reads here, one where you test and one where you
print. I suspect that if you add a dummy status read like Michael need to do:
stat = flash[0]; /* dummy, will contain garbage sometimes */
stat = flash[0];
if ((stat & 0x00800080) == 0x00800080) {
printf("\nstatus %08x\n", stat);
break;
}
You will see an improvement.
Michael, have you made any progress? Can you run Anders program too?
Jocke
More information about the linux-mtd
mailing list