Linux-mtd Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Bigler <stefan.bigler@keymile.com>
To: Joakim Tjernlund <joakim.tjernlund@transmode.se>
Cc: linux-mtd@lists.infradead.org,
	Holger brunck <holger.brunck@keymile.com>,
	Michael Cashwell <mboards@prograde.net>
Subject: Re: Numonyx NOR and chip->mutex bug?
Date: Mon, 07 Feb 2011 15:47:00 +0100	[thread overview]
Message-ID: <4D5005E4.1040506@keymile.com> (raw)
In-Reply-To: <OF2C1ABD39.CB78C79D-ONC125782F.0074C320-C125782F.007542AF@transmode.se>

Hi

I run the test on my side with the patches proposed with and without 
barrier().
Both worked without problems.

My workspace has now the following patches:

1) clear status before suspend
------------------------------
+    /* numonyx data sheet clearly says to always reset the status bits
+       before resuming a suspended erase. not doing so results in
+       an ambiguous mixture of status bits once the command ends. */
+    debug_map_write(map, CMD(0x50), adr);
+    debug_map_write(map, CMD(0xd0), adr);


2) compare chip>state and chip_state before touching the chip
------------------------------------------------------------

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index e89f2d0..73e29a3 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -1243,12 +1243,34 @@ static int inval_cache_and_wait_for_operation(
  		timeo = 500000;
  	reset_timeo = timeo;
  	sleep_time = chip_op_time / 2;
-
+	barrier(); /* make sure chip->state gets reloaded */
  	for (;;) {
+		if (chip->state != chip_state) {
+			/* Someone's suspended the operation: sleep */
+			DECLARE_WAITQUEUE(wait, current);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq,&wait);
+			mutex_unlock(&chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq,&wait);
+			mutex_lock(&chip->mutex);
+			continue;
+		}
+
  		status = map_read(map, cmd_adr);
  		if (map_word_andequal(map, status, status_OK, status_OK))
  			break;

+		if (chip->erase_suspended&&  chip_state == FL_ERASING)  {
+			/* Erase suspend occured while sleep: reset timeout */
+			timeo = reset_timeo;
+			chip->erase_suspended = 0;
+		}
+		if (chip->write_suspended&&  chip_state == FL_WRITING)  {
+			/* Write suspend occured while sleep: reset timeout */
+			timeo = reset_timeo;
+			chip->write_suspended = 0;
+		}
  		if (!timeo) {
  			map_write(map, CMD(0x70), cmd_adr);
  			chip->state = FL_STATUS;
@@ -1272,27 +1294,6 @@ static int inval_cache_and_wait_for_operation(
  			timeo--;
  		}
  		mutex_lock(&chip->mutex);
-
-		while (chip->state != chip_state) {
-			/* Someone's suspended the operation: sleep */
-			DECLARE_WAITQUEUE(wait, current);
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			add_wait_queue(&chip->wq,&wait);
-			mutex_unlock(&chip->mutex);
-			schedule();
-			remove_wait_queue(&chip->wq,&wait);
-			mutex_lock(&chip->mutex);
-		}
-		if (chip->erase_suspended&&  chip_state == FL_ERASING)  {
-			/* Erase suspend occured while sleep: reset timeout */
-			timeo = reset_timeo;
-			chip->erase_suspended = 0;
-		}
-		if (chip->write_suspended&&  chip_state == FL_WRITING)  {
-			/* Write suspend occured while sleep: reset timeout */
-			timeo = reset_timeo;
-			chip->write_suspended = 0;
-		}
  	}

3) Fix for errata regarding Flexlock Write Timing
-------------------------------------------------
This patch is not tested because the code is not called in my
test cases.

+       int ofs_factor = cfi->interleave * cfi->device_type;


+	/* address numonyx errata regarding Flexlock Write Timing.
+	   before doing a 0x60 lock/unlock sequence on a sector
+	   its current lock state needs to be read and the result
+          discarded. */
+       debug_map_write(map, CMD(0x90), adr+(2*ofs_factor));
+	chip->state = FL_JEDEC_QUERY;
+	(void) cfi_read_query(map, adr+(2*ofs_factor));


What are your plans?
Can I do some more tests?


Regards Stefan

Attached you find the small script creating a ubivolume write to it and delete it afterwards.

dd if=foofoo of=testfile bs=1024 count=1024
date
echo time ubimkvol /dev/ubi0 -s 6MiB -N test1
time ubimkvol /dev/ubi0 -s 6MiB -N test1
date
echo time cp testfile /dev/`cat /proc/mtd | grep test1 | sed 's/: .*//' | sed 's/mtd/mtdblock/'`
time cp testfile /dev/`cat /proc/mtd | grep test1 | sed 's/: .*//' | sed 's/mtd/mtdblock/'`
date
echo time ubirmvol /dev/ubi0 -N test1
time ubirmvol /dev/ubi0 -N test1


Am 02/06/2011 10:20 PM, schrieb Joakim Tjernlund:
> Michael Cashwell<mboards@prograde.net>  wrote on 2011/02/06 22:13:40:
>> On Feb 6, 2011, at 12:29 PM, Joakim Tjernlund wrote:
>>
>>> Michael Cashwell<mboards@prograde.net>  wrote on 2011/02/06 16:49:53:
>>>
>>>> That's clearly what's happening in Stefan's trace when thread 465 writes 0xe8 and the next write is 0x70 by thread 209. Such a sequence is absolutely illegal (for the flash) and the latter thread is the problem. If we could get a stack trace for that map_write 0x70 I think we'd find the thread
> awoke and touched the chip without verifying the state first. The question is why.
>>> Without my patch it is clear that you do end up with this problem. The first time one enter the for(;;) loop the driver reads out status from the chip before checking chip->state. This of course assumes that dropping the lock earlier may cause a schedule. So far Stefans tests indicates this to
> be true.
>> Yes, it was your patch and his log that lead me down that path!
>>
>>>> One last idea.
>>>>
>>>> The whole for(;;) loop in inval_cache_and_wait_for_operation() looks odd to me. Continuing with your idea of moving the chip->state while loop first, I see other problems. It seems to me that anywhere we drop and retake the chip mutex the very next thing needs to be the state check loop. Any
> break in holding that mutex means we must go back to the top and check state again.
>>>> I don't think the code as written does that. I have a completely reordered version of this function. (It didn't fix my issue but I think mine is something else.) On Monday I'll send that to you so you can consider it.
>>> Yes, it is a bit odd. In addition to my patch one could move the erase suspend tests before the if(!timeo) test.
>> Precisely. I suspect you may well already have my reordered version. :-)
> hehe, lets se(the barrier() is probably useless):
>
> diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
> index e89f2d0..73e29a3 100644
> --- a/drivers/mtd/chips/cfi_cmdset_0001.c
> +++ b/drivers/mtd/chips/cfi_cmdset_0001.c
> @@ -1243,12 +1243,34 @@ static int inval_cache_and_wait_for_operation(
>   		timeo = 500000;
>   	reset_timeo = timeo;
>   	sleep_time = chip_op_time / 2;
> -
> +	barrier(); /* make sure chip->state gets reloaded */
>   	for (;;) {
> +		if (chip->state != chip_state) {
> +			/* Someone's suspended the operation: sleep */
> +			DECLARE_WAITQUEUE(wait, current);
> +			set_current_state(TASK_UNINTERRUPTIBLE);
> +			add_wait_queue(&chip->wq,&wait);
> +			mutex_unlock(&chip->mutex);
> +			schedule();
> +			remove_wait_queue(&chip->wq,&wait);
> +			mutex_lock(&chip->mutex);
> +			continue;
> +		}
> +
>   		status = map_read(map, cmd_adr);
>   		if (map_word_andequal(map, status, status_OK, status_OK))
>   			break;
>
> +		if (chip->erase_suspended&&  chip_state == FL_ERASING)  {
> +			/* Erase suspend occured while sleep: reset timeout */
> +			timeo = reset_timeo;
> +			chip->erase_suspended = 0;
> +		}
> +		if (chip->write_suspended&&  chip_state == FL_WRITING)  {
> +			/* Write suspend occured while sleep: reset timeout */
> +			timeo = reset_timeo;
> +			chip->write_suspended = 0;
> +		}
>   		if (!timeo) {
>   			map_write(map, CMD(0x70), cmd_adr);
>   			chip->state = FL_STATUS;
> @@ -1272,27 +1294,6 @@ static int inval_cache_and_wait_for_operation(
>   			timeo--;
>   		}
>   		mutex_lock(&chip->mutex);
> -
> -		while (chip->state != chip_state) {
> -			/* Someone's suspended the operation: sleep */
> -			DECLARE_WAITQUEUE(wait, current);
> -			set_current_state(TASK_UNINTERRUPTIBLE);
> -			add_wait_queue(&chip->wq,&wait);
> -			mutex_unlock(&chip->mutex);
> -			schedule();
> -			remove_wait_queue(&chip->wq,&wait);
> -			mutex_lock(&chip->mutex);
> -		}
> -		if (chip->erase_suspended&&  chip_state == FL_ERASING)  {
> -			/* Erase suspend occured while sleep: reset timeout */
> -			timeo = reset_timeo;
> -			chip->erase_suspended = 0;
> -		}
> -		if (chip->write_suspended&&  chip_state == FL_WRITING)  {
> -			/* Write suspend occured while sleep: reset timeout */
> -			timeo = reset_timeo;
> -			chip->write_suspended = 0;
> -		}
>   	}
>
>   	/* Done and happy. */
>
>>>>> Oh, one more thing, possibly one needs to add cpu_relax() or similar to force gcc to reload chip->state in the while loop?
>>>> I was also wondering about possible gcc optimization issues. I'm on 4.5.2 and that worked for me with the 2003 flash part. The same binaries fail with the 2008 parts, so, I don't know.
>>> Very recent gcc, I am 3.4.6 but recently I began testing a little with 4.5.2. I do think I will wait for 4.5.3
>> I tried 4.5.1 but it failed for other reasons. I submitted bug reports to gnu and a fix appeared (finally) in 4.5.2. It's been good so far but I'm always mindful of that issue.
>>
>> Staying current is a two edge sword. In general, later gccs have better code analysis and warnings which are valuable even if we ship using an older version.
> Precisely, but later gcc is worse optimizing trivial code.
>
>>>> Keep in mind that chip->state is not a hardware access. It's just another struct member. And I think that the rules are that any function call counts as a sequence point and gcc isn't allowed to think it knows what the result is and must reload it.
>>>>
>>>> Lastly, consider the direction of the behavior. If we're in the state-check while loop then we got there because the two things were NOT equal. If an optimization error is causing a stale value to be compared wouldn't the observed behavior be that it remains not equal? (If it's not reloaded
> then how could it change?)
>>>> I'd expect an optimization error like that to get us stuck in the while loop, not exit from it prematurely.
>>> Yes, all true. I wonder though if the mutex lock/unlock counts as a reload point? These are usually some inline asm. If not one could possibly argue that the first chip->state access, before entering the while body is using an old value.
>> Yes, how inlines interact with sequence points has never been entirely clear to me. Especially since the compiler is free to inline something I didn't tell it to and to ignore me telling to inline if it wants to.
>>
>> I *think* the rules are semantic. If it's written (preprocessor aside) to look like a function call then it counts as a sequence point even if it ends up being inlined. But that's all quite beyond anything I can say for sure!
> That makes sense too.
>
>>>> Makes me head hurt!
>>> You are not alone :)
>> So collectively maybe we can make it hurt less. That's my theory, anyway, and I'm sticking to it.
> :)
>

  reply	other threads:[~2011-02-07 14:47 UTC|newest]

Thread overview: 76+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-25 18:14 Numonyx NOR and chip->mutex bug? Michael Cashwell
2011-01-25 18:56 ` Joakim Tjernlund
2011-01-25 22:03   ` Michael Cashwell
2011-01-25 23:09     ` Joakim Tjernlund
2011-02-02 16:20       ` Michael Cashwell
2011-02-02 17:37         ` Stefan Bigler
2011-02-02 20:12         ` Joakim Tjernlund
2011-02-02 21:19           ` Michael Cashwell
2011-02-03  8:11             ` Joakim Tjernlund
2011-02-03  9:50               ` Joakim Tjernlund
2011-02-03 15:24                 ` Michael Cashwell
2011-02-03 16:38                   ` Stefan Bigler
2011-02-03 23:18                     ` Stefan Bigler
2011-02-04 10:47                       ` Joakim Tjernlund
2011-02-04 11:04                         ` Stefan Bigler
2011-02-04 12:26                           ` Joakim Tjernlund
2011-02-04 12:35                             ` Joakim Tjernlund
2011-02-04 12:42                               ` Joakim Tjernlund
2011-02-04 13:05                           ` Joakim Tjernlund
2011-02-04 13:25                             ` Joakim Tjernlund
2011-02-04 16:45                             ` Stefan Bigler
2011-02-04 16:55                               ` Joakim Tjernlund
2011-02-04 17:09                             ` Michael Cashwell
     [not found]                               ` <OF42EF<F66AF016-8A2B-4116-BE49-CE05B91BE50F@prograde.net>
     [not found]                               ` <OF42EF <F66AF016-8A2B-4116-BE49-CE05B91BE50F@prograde.net>
2011-02-05 10:29                               ` Joakim Tjernlund
2011-02-05 19:19                                 ` Michael Cashwell
2011-02-05 21:47                                   ` Michael Cashwell
2011-02-06  9:46                                     ` Joakim Tjernlund
2011-02-06 15:49                                       ` Michael Cashwell
2011-02-06 17:29                                         ` Joakim Tjernlund
2011-02-06 21:13                                           ` Michael Cashwell
     [not found]                                             ` <OF2C1ABD39 <4D5005E4.1040506@keymile.com>
     [not found]                                               ` <OFFF2C6D34.91E5D6C3-ONC1257 <96BD3889-E8AD-408D-8275-ED1A5FD55F1B@prograde.net>
     [not found]                                             ` <OF2C1ABD39<4D5005E4.1040506@keymile.com>
     [not found]                                               ` <OFFF2C6D34.91E5D6C3-ONC1257<96BD3889-E8AD-408D-8275-ED1A5FD55F1B@prograde.net>
     [not found]                                                 ` <OF9738D658.F46<4C117A67-5057-4ACD-8EBE-04E9C782570C@prograde.net>
     [not found]                                                   ` <OF6D40AC82.1008D3DD-ONC1 <4D53E660.4020305@users.sourceforge.net>
2011-02-06 21:20                                             ` Joakim Tjernlund
2011-02-07 14:47                                               ` Stefan Bigler [this message]
2011-02-07 15:01                                                 ` Joakim Tjernlund
2011-02-07 15:46                                                   ` Michael Cashwell
2011-02-07 15:52                                                     ` Stefan Bigler
2011-02-07 16:22                                                     ` Joakim Tjernlund
2011-02-07 16:46                                                       ` Michael Cashwell
2011-02-07 17:08                                                         ` Stefan Bigler
2011-02-07 19:04                                                           ` Michael Cashwell
2011-02-09 19:52                                                             ` Michael Cashwell
2011-02-09 20:13                                                               ` Joakim Tjernlund
2011-02-09 21:59                                                                 ` Michael Cashwell
2011-02-10 13:21                                                                   ` Anders Grafström
2011-02-10 14:04                                                                     ` Joakim Tjernlund
2011-02-10 15:04                                                                       ` Joakim Tjernlund
2011-02-10 15:59                                                                         ` Michael Cashwell
2011-02-10 16:05                                                                           ` Joakim Tjernlund
2011-02-10 16:41                                                                             ` Michael Cashwell
2011-02-10 16:46                                                                               ` Joakim Tjernlund
2011-02-10 17:02                                                                                 ` Joakim Tjernlund
2011-02-10 17:10                                                                                   ` Michael Cashwell
2011-02-10 17:20                                                                                     ` Joakim Tjernlund
2011-02-10 17:47                                                                                       ` Joakim Tjernlund
2011-02-10 18:26                                                                                         ` Joakim Tjernlund
2011-02-11 18:03                                                                                           ` Michael Cashwell
2011-02-12 10:47                                                                                             ` Joakim Tjernlund
2011-02-14 15:59                                                                                         ` Michael Cashwell
2011-02-14 15:44                                                                                       ` Michael Cashwell
2011-02-10 16:43                                                                           ` Michael Cashwell
2011-02-10 17:54                                                                             ` Anders Grafström
2011-02-11 15:05                                                                               ` Michael Cashwell
2011-02-11 15:39                                                                                 ` Joakim Tjernlund
2011-02-14 16:15                                                                                   ` Michael Cashwell
2011-02-11 17:00                                                                               ` Joakim Tjernlund
2011-02-10 15:43                                                                       ` Michael Cashwell
2011-02-10 15:51                                                                         ` Joakim Tjernlund
2011-02-24 10:50                                                                     ` Joakim Tjernlund
2011-02-24 11:36                                                                       ` Joakim Tjernlund
2011-02-24 14:28                                                                       ` Michael Cashwell
2011-02-10 14:53                                                                   ` Joakim Tjernlund
2011-02-06  9:40                                   ` Joakim Tjernlund
2011-02-06 14:55                                     ` Michael Cashwell
2011-02-07 15:10                                   ` Michael Cashwell
2011-02-07 15:48                                     ` Joakim Tjernlund
2011-02-03 13:24               ` Michael Cashwell
2011-02-03 14:01                 ` Joakim Tjernlund

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D5005E4.1040506@keymile.com \
    --to=stefan.bigler@keymile.com \
    --cc=holger.brunck@keymile.com \
    --cc=joakim.tjernlund@transmode.se \
    --cc=linux-mtd@lists.infradead.org \
    --cc=mboards@prograde.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox