public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
From: Ilya Yanok <yanok@emcraft.com>
To: linux-mtd@lists.infradead.org
Subject: [RFC] Handling of errors for AMD NOR (cfi_cmdset_0002) chips
Date: Fri, 11 Mar 2011 04:42:59 +0300	[thread overview]
Message-ID: <4D797E23.6070409@emcraft.com> (raw)

Hello,

current cfi_cmdset_0002.c code does not implement handling of error 
statuses reported by the chip during write/erase and just waits for a 
software timeout instead.

We think that proper handling of these conditions could help us to debug 
the issue we have with the NOR flash and UBIFS so we'd like to implement 
such handling.

I've tried to do this, please see my initial patch below. For now errors 
are just reported via pr_debug().

I'd like to hear any comments. Am I doing things right or not? Maybe I'm 
missing something?

Here is the patch:

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c 
b/drivers/mtd/chips/cfi_cmdset_0002.c
index 156aaa6..804cfc9 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -507,6 +507,78 @@ static struct mtd_info *cfi_amdstd_setup(struct 
mtd_info *mtd)
         return NULL;
  }

+static u32 get_chip_status(struct map_info *map, map_word val, int n)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       int wordwidth, words_per_bus, chip_mode, chips_per_word;
+       unsigned long onestat;
+       u32 res;
+
+       BUG_ON(n >= cfi_interleave(cfi));
+
+       if (map_bankwidth_is_large(map)) {
+               wordwidth = sizeof(unsigned long);
+               words_per_bus = (map_bankwidth(map)) / wordwidth; // 
i.e. normally 1
+       } else {
+               wordwidth = map_bankwidth(map);
+               words_per_bus = 1;
+       }
+
+       chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
+       chips_per_word = wordwidth * cfi_interleave(cfi) / 
map_bankwidth(map);
+
+       onestat = val.x[n/chips_per_word];
+       onestat >>= chip_mode * 8 * (n % chips_per_word);
+
+       res = (u32) onestat;
+
+       /* Last, determine what the bit-pattern should be for a single
+          device, according to chip mode and endianness... */
+       switch (chip_mode) {
+       case 1:
+               break;
+       case 2:
+               res = cfi16_to_cpu(res);
+               break;
+       case 4:
+               res = cfi32_to_cpu(res);
+               break;
+       default: BUG();
+       }
+       return res;
+}
+
+/*
+ * Chip statuses
+ */
+#define CHIP_READY     0
+#define CHIP_BUSY      1
+#define CHIP_TIMEOUT   2
+#define CHIP_ABORT     3
+
+static int check_chip(struct map_info *map, int n, map_word read_1,
+               map_word read_2, map_word read_3)
+{
+       u32 r1 = get_chip_status(map, read_1, n);
+       u32 r2 = get_chip_status(map, read_2, n);
+       u32 r3 = get_chip_status(map, read_3, n);
+
+       if ((r1 == r2) && (r2 == r3))
+               return CHIP_READY;
+
+       if (r1 & (1 << 1)) {
+               pr_debug("Write abort on chip %d\n", n);
+               return CHIP_ABORT;
+       }
+
+       if (r1 & (1 << 5)) {
+               pr_debug("Timeout on chip %d\n",n);
+               return CHIP_TIMEOUT;
+       }
+
+       return CHIP_BUSY;
+}
+
  /*
   * Return true if the chip is ready.
   *
@@ -520,12 +592,17 @@ static struct mtd_info *cfi_amdstd_setup(struct 
mtd_info *mtd)
   */
  static int __xipram chip_ready(struct map_info *map, unsigned long addr)
  {
-       map_word d, t;
+       struct cfi_private *cfi = map->fldrv_priv;
+       map_word r1, r2, r3;
+       int i, res = 0;

-       d = map_read(map, addr);
-       t = map_read(map, addr);
+       r1 = map_read(map, addr);
+       r2 = map_read(map, addr);
+       r3 = map_read(map, addr);

-       return map_word_equal(map, d, t);
+       for (i = 0; i < cfi_interleave(cfi); i++)
+               res += check_chip(map, i, r1, r2, r3);
+       return !res;
  }

  /*

Thanks!

Regards, Ilya.

             reply	other threads:[~2011-03-11  1:43 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-11  1:42 Ilya Yanok [this message]
2011-03-11  8:25 ` [RFC] Handling of errors for AMD NOR (cfi_cmdset_0002) chips Norbert van Bolhuis
2011-03-23 15:47   ` Detlev Zundel
2011-03-23 17:33     ` Artem Bityutskiy
2011-03-24  7:35     ` Norbert van Bolhuis
2011-03-24  9:27       ` Detlev Zundel
2011-03-24 10:48         ` Norbert van Bolhuis
2011-03-15  8:01 ` Markus Niebel
2011-03-23 16:16   ` Detlev Zundel
2011-03-23 18:27   ` Ilya Yanok
2011-03-24  7:45 ` Alexander Stein
2011-03-24  7:55   ` Artem Bityutskiy

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=4D797E23.6070409@emcraft.com \
    --to=yanok@emcraft.com \
    --cc=linux-mtd@lists.infradead.org \
    /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