From jg1.han at samsung.com  Sat Jun  1 03:17:37 2013
From: jg1.han at samsung.com (Jingoo Han)
Date: Sat, 01 Jun 2013 16:17:37 +0900
Subject: [PATCH] mtd: mtdswap: replace strict_strtoul() with kstrtoul()
Message-ID: <000c01ce5e98$18483b70$48d8b250$@samsung.com>

The usage of strict_strtoul() is not preferred, because
strict_strtoul() is obsolete. Thus, kstrtoul() should be
used.

Signed-off-by: Jingoo Han <jg1.han at samsung.com>
---
 drivers/mtd/mtdswap.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index c92f0f6..8b33b26 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -1425,7 +1425,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 		return;
 
 	while ((this_opt = strsep(&parts, ",")) != NULL) {
-		if (strict_strtoul(this_opt, 0, &part) < 0)
+		if (kstrtoul(this_opt, 0, &part) < 0)
 			return;
 
 		if (mtd->index == part)
-- 
1.7.10.4




From renner at efe-gmbh.de  Sun Jun  2 11:53:13 2013
From: renner at efe-gmbh.de (Jens Renner (EFE))
Date: Sun, 02 Jun 2013 17:53:13 +0200
Subject: [PATCH v2] mtd: Add LED trigger support "mtd-disk" to indicate
 activity
Message-ID: <51AB6A69.9080004@efe-gmbh.de>

Register a MTD LED trigger called "mtd-disk" (similar to the "ide-disk" and
"nand-disk" triggers) to indicate read / write / erase acitivity. Panic writes
and OOB reads / writes are not covered as of now. The trigger is global as it
does not discriminate between individual devices or partitions.
The patch uses the generic LED trigger interface which can be configured via
SYSFS (/sys/class/leds/<name>/trigger) or DTS file entry for "gpio-leds"
(linux,default-trigger = "mtd-disk").

Since the MTD framework is independant of the memory devices, driver-specific
LED triggers like "nand-disk" will indicate a subset of all MTD activity.

Tested on Microblaze architecture with Micron N25Q256A serial flash.
Added a bit of documentation (including other new LED triggers).

Signed-off-by: Jens Renner <renner at efe-gmbh.de>
---
Changes in v2:
- fix whitespace problem

 drivers/mtd/mtdcore.c                                          |   25 ++++++++++++++++++--
 Documentation/devicetree/bindings/leds/common.txt              |    4 ++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c400c57..fbf1ed8 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -37,6 +37,7 @@
 #include <linux/backing-dev.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -100,6 +101,8 @@ static LIST_HEAD(mtd_notifiers);
 
 #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
 
+DEFINE_LED_TRIGGER(mtd_led_trigger);
+
 /* REVISIT once MTD uses the driver model better, whoever allocates
  * the mtd_info will probably want to use the release() hook...
  */
@@ -727,6 +730,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
  */
 int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
+	int ret_code;
 	if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
 		return -EINVAL;
 	if (!(mtd->flags & MTD_WRITEABLE))
@@ -737,7 +741,11 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 		mtd_erase_callback(instr);
 		return 0;
 	}
-	return mtd->_erase(mtd, instr);
+	led_trigger_event(mtd_led_trigger, LED_FULL);
+	ret_code = mtd->_erase(mtd, instr);
+	led_trigger_event(mtd_led_trigger, LED_OFF);
+
+	return ret_code;
 }
 EXPORT_SYMBOL_GPL(mtd_erase);
 
@@ -800,12 +808,17 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
 	if (!len)
 		return 0;
 
+	led_trigger_event(mtd_led_trigger, LED_FULL);
+
 	/*
 	 * In the absence of an error, drivers return a non-negative integer
 	 * representing the maximum number of bitflips that were corrected on
 	 * any one ecc region (if applicable; zero otherwise).
 	 */
 	ret_code = mtd->_read(mtd, from, len, retlen, buf);
+
+	led_trigger_event(mtd_led_trigger, LED_OFF);
+
 	if (unlikely(ret_code < 0))
 		return ret_code;
 	if (mtd->ecc_strength == 0)
@@ -817,6 +830,7 @@ EXPORT_SYMBOL_GPL(mtd_read);
 int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 	      const u_char *buf)
 {
+	int ret_code;
 	*retlen = 0;
 	if (to < 0 || to > mtd->size || len > mtd->size - to)
 		return -EINVAL;
@@ -824,7 +838,11 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 		return -EROFS;
 	if (!len)
 		return 0;
-	return mtd->_write(mtd, to, len, retlen, buf);
+	led_trigger_event(mtd_led_trigger, LED_FULL);
+	ret_code = mtd->_write(mtd, to, len, retlen, buf);
+	led_trigger_event(mtd_led_trigger, LED_OFF);
+
+	return ret_code;
 }
 EXPORT_SYMBOL_GPL(mtd_write);
 
@@ -1187,6 +1205,8 @@ static int __init init_mtd(void)
 	if (ret)
 		goto out_procfs;
 
+	led_trigger_register_simple("mtd-disk", &mtd_led_trigger);
+
 	return 0;
 
 out_procfs:
@@ -1205,6 +1225,7 @@ err_reg:
 
 static void __exit cleanup_mtd(void)
 {
+	led_trigger_unregister_simple(mtd_led_trigger);
 	cleanup_mtdchar();
 	if (proc_mtd)
 		remove_proc_entry("mtd", NULL);
diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
index 2d88816..9875cd2 100644
--- a/Documentation/devicetree/bindings/leds/common.txt
+++ b/Documentation/devicetree/bindings/leds/common.txt
@@ -12,6 +12,10 @@ Optional properties for child nodes:
 		    property in Documentation/devicetree/bindings/gpio/led.txt)
      "heartbeat" - LED "double" flashes at a load average based rate
      "ide-disk" - LED indicates disk activity
+     "mtd-disk" - LED indicates MTD activity
+     "nand-disk" - LED indicates NAND activity
+     "mmc<n>" - LED indicates activity of SD/MMC #n (e.g. "mmc0")
+     "cpu<n>" - LED indicates activity of CPU #n (e.g. "cpu0")
      "timer" - LED flashes at a fixed, configurable rate
 
 Examples:


From josh.wu at atmel.com  Mon Jun  3 01:44:00 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 3 Jun 2013 13:44:00 +0800
Subject: [PATCH] MTD: atmel_nand: using a stronger ECC is not dangerous
In-Reply-To: <1370010850-20860-1-git-send-email-richard.genoud@gmail.com>
References: <1370010850-20860-1-git-send-email-richard.genoud@gmail.com>
Message-ID: <51AC2D20.3040703@atmel.com>

On 5/31/2013 10:34 PM, Richard Genoud wrote:
> We don't have to issue a warning when a stronger error correting
> capability is chosen.
>
> Signed-off-by: Richard Genoud <richard.genoud at gmail.com>

Acked-by: Josh Wu <josh.wu at atmel.com>

Best Regards,
Josh Wu

> ---
>   drivers/mtd/nand/atmel_nand.c |    2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index 2d23d29..2415cdc 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -1002,7 +1002,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
>   		return err_no;
>   	}
>   
> -	if (cap != host->pmecc_corr_cap ||
> +	if (cap > host->pmecc_corr_cap ||
>   			sector_size != host->pmecc_sector_size)
>   		dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
>   



From dedekind1 at gmail.com  Mon Jun  3 02:01:22 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Mon, 03 Jun 2013 09:01:22 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
Message-ID: <1370239282.21714.21.camel@sauron.fi.intel.com>

On Fri, 2013-05-31 at 11:51 +0200, Prins Anton (ST-CO/ENG1.1) wrote:
> Hi Artem,
> 
> Some questions regarding this issue:
> - The orphan area is fixed size, in the implementation we unlink/delete a file 4 times a second... could there be any relation?
>   (How can we calculate the required orphan area size in LEBs?)

No, we stress-tested it with a lot more frequent deletions. I cannot
answer about size calculation off the top of my head, I'd need to read
the code and try calculating. But I guess it is easier to find this out
by writing a small test program which will create create/open/unlink
files until it fails. And you can experiment with amount of orphan LEBs
ans find all the numbers. You can also share them with us :-)

> - Initial the three file systems are programmed if 'flat-image' (ubinized and free space fix-up) from U-boot; can there be an issue?

There were several free space fix-up bug-fixes recently.

I wonder if you have these patches:

0c6c7fa1313fcb69cae35e34168d2e83b8da854a
fe96efc1a3c049f0a1bcd9b65e0faeb751ce5ec6

They prevent from unpleasant bugs in flashers - when you flash a new
image to a flash which alsready contains some UBI stuff, and flasher
does not erase some eraseblocks, the old contents may be treated as part
of the new image, causing really random and subtle problems.

>   (Every ubi-filesystem has its own MTD, so I guess partition separation is guaranteed by the MTD-layer).

Should be.

> - How can I find the orphan LEB(s), to send you some 'contents'?

The LEB numbers range is:

[c->orph_first, c->orph_last]

So all LEBs from c->orph_first to c->orph_last are orphan LEBs.

You can inject printk and print the numbers.

Then you can read the corresponding LEBs directly from /dev/ubiX_Y using
dd. You'll just need to calculate offsets. Offset is LEB number * LEB
size.

-- 
Best Regards,
Artem Bityutskiy



From dedekind1 at gmail.com  Mon Jun  3 05:39:38 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Mon, 03 Jun 2013 12:39:38 +0300
Subject: [PATCH] mtd: mtdchar: Exit write loop when hitting end of OTP
 memory
In-Reply-To: <51A6103B.7010201@omicron.at>
References: <29483dd6-387c-4b28-b689-88795e0bbbde@mary.at.omicron.at>
 <1369811298.5446.215.camel@sauron.fi.intel.com>
 <51A60071.2060005@omicron.at>
 <1369835798.24286.34.camel@sauron.fi.intel.com>
 <51A6103B.7010201@omicron.at>
Message-ID: <1370252378.21714.28.camel@sauron.fi.intel.com>

On Wed, 2013-05-29 at 16:27 +0200, Christian Riesch wrote:
> [cc'ed the author of onenand otp support]
> 
> On 2013-05-29 15:56, Artem Bityutskiy wrote:
> > On Wed, 2013-05-29 at 15:19 +0200, Christian Riesch wrote:
> >> The OTP code for the AMD command set in my recent patchset is modeled
> >> after the existing code in drivers/mtd/chips/cfi_cmdset_0001.c.
> >> Therefore it has a ...walk() function that walks from chip to chip and
> >> tries to write as much data as possible into the OTP memories of these
> >> chips. Until the last iteration of this loop it does not know how much
> >> OTP memory is available. Therefore, a check for insufficient OTP memory
> >> and returning an error before writing any data is not possible.
> >>
> >> Of course I could change my code to obtain the available OTP memory
> >> before writing any data. But then the code in cfi_cmdset_0001.c would
> >> still suffer from this issue.
> >
> > Could you please check OneNAND and other drivers which implement OTP and
> > see whether they check for space availability?
> 
> mtd->_write_user_prot_reg is currently implemented by 
> drivers/mtd/chips/cfi_cmdset_0001.c, drivers/mtd/onenand/onenand_base.c, 
> and drivers/mtd/devices/mtd_dataflash.c.
> 
> mtd_dataflash checks if the offset is larger than 64 and returns -EINVAL 
> in this case. If offset <= 64, but offset + len > 64, len is decreased 
> to fit into the OTP memory, the number of actually written bytes is 
> returned. It therefore suffers from the same issue in mtdchar.c as the 
> Intel command set.
> 
> onenand seems to do some kind of length check (although I do not fully 
> understand why it does not include the offset in 'from' in this check if 
> the factory OTP is addressed), but if the data does not fit into the 
> memory it returns 0 instead of an error code, resulting in an infinite 
> loop as well.

Would you be able to harmonize the implementations and switch them all
to the interface which is consistent with normal read/write, i.e., has
the retlen parameter?
 
-- 
Best Regards,
Artem Bityutskiy



From dedekind1 at gmail.com  Mon Jun  3 05:40:14 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Mon, 03 Jun 2013 12:40:14 +0300
Subject: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
In-Reply-To: <51A61274.70607@omicron.at>
References: <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
 <38c84e40-1171-4040-bc8b-ec51a0485819@mary.at.omicron.at>
 <1369811482.5446.216.camel@sauron.fi.intel.com>
 <51A5FA84.8030906@omicron.at>
 <1369835589.24286.31.camel@sauron.fi.intel.com> <51A61274.70607@omicron.at>
Message-ID: <1370252414.21714.29.camel@sauron.fi.intel.com>

On Wed, 2013-05-29 at 16:36 +0200, Christian Riesch wrote:
> > But retlen is where you return the amount of bytes you actually
> wrote.
> > The return code is either 0 or a negative error code number. This is
> > what we do in mtd_write() and I'd expect the OTP functions to be
> > consistent.
> 
> Unlike mtd_write, mtd->_get_fact_prot_info (which is a pointer to 
> cfi_amdstd_get_fact_prot_info here) does not have a retlen parameter.
> Do 
> you suggest to change this?

Yes, I would suggest this.

-- 
Best Regards,
Artem Bityutskiy



From richard.genoud at gmail.com  Mon Jun  3 08:48:55 2013
From: richard.genoud at gmail.com (Richard Genoud)
Date: Mon, 3 Jun 2013 14:48:55 +0200
Subject: UBI torture_peb() bad block detection problem
In-Reply-To: <CAKGbVbux-d6xfmSahryTwDokRT0SaZUqgD3oHUQ8rP+tMyy1_A@mail.gmail.com>
References: <CAKGbVbtp4FBauCFNGSPTQSk_Dz4ELa7Gn31UByTMaFSk_vF1eg@mail.gmail.com>
 <CACQ1gAis_qrt_7RTROw-Hbueiy0XKYwtyR56w2DkajVKvwwwHA@mail.gmail.com>
 <CAKGbVbux-d6xfmSahryTwDokRT0SaZUqgD3oHUQ8rP+tMyy1_A@mail.gmail.com>
Message-ID: <CACQ1gAhN=svvZMnq7xySgZvcmVk=pvrFNFsxY_ghxkQz-E3rAQ@mail.gmail.com>

2013/5/31 Qiang Yu <yuq825 at gmail.com>:
> Here is my driver, and it can now be used with UBI+UBIFS.
> https://github.com/yuq/sunxi-nfc-mtd

I had a look at your driver, it seems that you forgot to set ecc.strenght.
take a look at this driver for instance: drivers/mtd/nand/jz4740_nand.c
the chip->ecc.strength is set to the max correctable bitflips.
The ecc.correct function returns the actual number of bitflips that
happened during reading.
And as Artem said, the mtd layer returns an error only if ret_code >=
mtd->bitflip_threshold ? -EUCLEAN : 0;
(and bitflip_threshold is == ecc.strenght in nand)

Richard.


From Mats.Karrman at tritech.se  Mon Jun  3 09:03:04 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Mon, 3 Jun 2013 13:03:04 +0000
Subject: UBIFS: Orphaned inode 1
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8BF32@post.tritech.se>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FC8BF32@post.tritech.se>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FC8C034@post.tritech.se>

Hi,

I'm facing a problem involving systems running in the field that suddenly cannot
boot anymore because the root UBIFS file system residing in a NOR flash
cannot be mounted. Error msg in kernel log is:

UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2

I have managed to copy a failing FLASH image into a file on my PC, uploaded it
to an mtdram device and tried to mount it with all debug info turned on and
"general" checks enabled. The final error is the same:

< snip >
[ 5513.523872] UBIFS: mounted UBI device 0, volume 0, name "debug-rootfs"
[ 5513.523878] UBIFS: file system size:   57877248 bytes (56520 KiB, 55 MiB, 442 LEBs)
[ 5513.523882] UBIFS: journal size:       8773248 bytes (8567 KiB, 8 MiB, 67 LEBs)
[ 5513.523885] UBIFS: media format:       w4/r0 (latest is w4/r0)
[ 5513.523887] UBIFS: default compressor: lzo
[ 5513.523893] UBIFS: reserved for root:  261902 bytes (255 KiB)
[ 5513.523896] UBIFS DBG (pid 4659): mount_ubifs: compiled on:         May 31 2013 at 13:31:25
[ 5513.523900] UBIFS DBG (pid 4659): mount_ubifs: min. I/O unit size:  8 bytes
[ 5513.523903] UBIFS DBG (pid 4659): mount_ubifs: max. write size:     64 bytes
[ 5513.523905] UBIFS DBG (pid 4659): mount_ubifs: LEB size:            130944 bytes (127 KiB)
[ 5513.523908] UBIFS DBG (pid 4659): mount_ubifs: data journal heads:  1
[ 5513.523911] UBIFS DBG (pid 4659): mount_ubifs: UUID:                B43E1323-1747-41FB-9C11-F4C0E59C24B8
[ 5513.523914] UBIFS DBG (pid 4659): mount_ubifs: big_lpt              0
[ 5513.523916] UBIFS DBG (pid 4659): mount_ubifs: log LEBs:            4 (3 - 6)
[ 5513.523919] UBIFS DBG (pid 4659): mount_ubifs: LPT area LEBs:       2 (7 - 8)
[ 5513.523921] UBIFS DBG (pid 4659): mount_ubifs: orphan area LEBs:    1 (9 - 9)
[ 5513.523924] UBIFS DBG (pid 4659): mount_ubifs: main area LEBs:      442 (10 - 451)
[ 5513.523926] UBIFS DBG (pid 4659): mount_ubifs: index LEBs:          32
[ 5513.523935] UBIFS DBG (pid 4659): mount_ubifs: total index bytes:   622720 (608 KiB, 0 MiB)
[ 5513.523940] UBIFS DBG (pid 4659): mount_ubifs: key hash type:       0
[ 5513.523944] UBIFS DBG (pid 4659): mount_ubifs: tree fanout:         8
[ 5513.523949] UBIFS DBG (pid 4659): mount_ubifs: reserved GC LEB:     443
[ 5513.523953] UBIFS DBG (pid 4659): mount_ubifs: first main LEB:      10
[ 5513.523958] UBIFS DBG (pid 4659): mount_ubifs: max. znode size      320
[ 5513.523964] UBIFS DBG (pid 4659): mount_ubifs: max. index node size 192
[ 5513.523967] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          data 48, inode 160, dentry 56
[ 5513.523970] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          trun 56, sb 4096, master 512
[ 5513.523973] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          ref 64, cmt. start 32, orph 32
[ 5513.523977] UBIFS DBG (pid 4659): mount_ubifs: max. node sizes:     data 4144, inode 4256 dentry 312, idx 188
[ 5513.523979] UBIFS DBG (pid 4659): mount_ubifs: dead watermark:      56
[ 5513.523982] UBIFS DBG (pid 4659): mount_ubifs: dark watermark:      4256
[ 5513.523984] UBIFS DBG (pid 4659): mount_ubifs: LEB overhead:        2480
[ 5513.523987] UBIFS DBG (pid 4659): mount_ubifs: max. dark space:     1881152 (1837 KiB, 1 MiB)
[ 5513.523989] UBIFS DBG (pid 4659): mount_ubifs: maximum bud bytes:   8249472 (8056 KiB, 7 MiB)
[ 5513.523992] UBIFS DBG (pid 4659): mount_ubifs: BG commit bud bytes: 6702696 (6545 KiB, 6 MiB)
[ 5513.523995] UBIFS DBG (pid 4659): mount_ubifs: current bud bytes    90112 (88 KiB, 0 MiB)
[ 5513.523998] UBIFS DBG (pid 4659): mount_ubifs: max. seq. number:    23851433
[ 5513.524000] UBIFS DBG (pid 4659): mount_ubifs: commit number:       1769
[ 5513.524003] ubifs_iget: UBIFS DBG gen: inode 1
[ 5513.524011] ubifs_lookup_level0: UBIFS DBG tnc: search key (1, inode)
[ 5513.524015] ubifs_lookup_level0: UBIFS DBG tnc: found 0, lvl 0, n -1
[ 5513.524018] UBIFS error (pid 4659): ubifs_iget: failed to read inode 1, error -2
[ 5513.524022] ubifs_evict_inode: UBIFS DBG gen: inode 1, mode 0x8000
[ 5513.524026] ubifs_umount: UBIFS DBG gen: un-mounting UBI device 0, volume 0
[ 5513.524049] UBIFS DBG (pid 4660): ubifs_bg_thread: background thread "ubifs_bgt0_0" stops

If i grep the log for recovery messages I get:

[ 5513.520324] UBIFS: recovery needed
[ 5513.520327] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking index head at 449:109136
[ 5513.520343] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking LPT head at 7:123208
[ 5513.520983] ubifs_recover_leb: UBIFS DBG rcvry: 219:93032, jhead 0, grouped 0
[ 5513.521039] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
[ 5513.521073] clean_buf: UBIFS DBG rcvry: cleaning corruption at 219:93032
[ 5513.521079] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 219 start 93032 endpt 93032
[ 5513.521396] ubifs_recover_leb: UBIFS DBG rcvry: 369:83568, jhead 1, grouped 1
[ 5513.521474] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
[ 5513.521548] clean_buf: UBIFS DBG rcvry: cleaning corruption at 369:83568
[ 5513.521557] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 369 start 83568 endpt 83568
[ 5513.521853] ubifs_recover_leb: UBIFS DBG rcvry: 444:126120, jhead 2, grouped 1
[ 5513.521919] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
[ 5513.521952] clean_buf: UBIFS DBG rcvry: cleaning corruption at 444:126120
[ 5513.521968] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 444 start 126120 endpt 126120
[ 5513.522770] kill_orphans: UBIFS DBG rcvry: LEB 9
[ 5513.522885] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1208852
[ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1
[ 5513.523489] do_kill_orphans: UBIFS DBG rcvry: last orph node for commit 1700 at 9:0
[ 5513.523494] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC head LEB 219, offs 93032
[ 5513.523512] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: committing
[ 5513.523768] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC'ing LEB 443
[ 5513.523840] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: allocated LEB 443 for GC
[ 5513.523843] UBIFS: recovery completed

The message that caught my attention:

[ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1

How can inode 1 be an orphan, or rather shouldn't it be?
Is it possible for a user-space application to cause this error?
Should I also look in UBI and MTD layers for the cause?
I'm not sure where to go on from here, any suggestions are welcome!!

My target system runs a Freescale MPC5125 (PPC e300c4) with a Linux 2.6.35.14
kernel patched with all UBFS patches from Artem's 2.6.35 maintenance tree and
additional ones from later kernel versions.
My PC runs the latest LMDE (3.2.32) recompiled with dynamic debug turned on.

BR // Mats


From computersforpeace at gmail.com  Mon Jun  3 21:46:44 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon,  3 Jun 2013 18:46:44 -0700
Subject: [PATCH 1/3] mtd: cfi_cmdset_0002: remove unnecessary initialization
Message-ID: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>

These timeout initializations are arbitrary and pointless. We simply
overwrite them with new values anyway. (In one case, the variable is not
ever even used, so we kill it.)

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 89b9d68..6c85f61 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1146,7 +1146,6 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
 static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	unsigned long timeo = jiffies + HZ;
 	struct cfi_private *cfi = map->fldrv_priv;
 
  retry:
@@ -1160,7 +1159,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
 
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
 
 		goto retry;
 	}
@@ -1228,7 +1226,7 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
 static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long timeo = jiffies + HZ;
+	unsigned long timeo;
 	/*
 	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices
 	 * have a max write time of a few hundreds usec). However, we should
@@ -1466,7 +1464,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 				    int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long timeo = jiffies + HZ;
+	unsigned long timeo;
 	/* see comments in do_write_oneword() regarding uWriteTimeo. */
 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
 	int ret = -EIO;
@@ -1900,7 +1898,7 @@ static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
 static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long timeo = jiffies + HZ;
+	unsigned long timeo;
 	unsigned long int adr;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
@@ -1990,7 +1988,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long timeo = jiffies + HZ;
+	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
 
-- 
1.8.2.3



From computersforpeace at gmail.com  Mon Jun  3 21:46:45 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon,  3 Jun 2013 18:46:45 -0700
Subject: [PATCH 2/3] mtd: cfi_cmdset_0002: use msecs_to_jiffies() macro
In-Reply-To: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
Message-ID: <1370310406-413-2-git-send-email-computersforpeace@gmail.com>

Rather than a bunch of calculations based on HZ, which are error-prone
and subject to "+ 1" (to avoid a 0 result), just use the
msecs_to_jiffies() macro. This makes both the intent (to wait some
approximate number of milliseconds) and the calculation clearer.

During the conversion, I noticed two places where we convert from
milliseconds to jiffies to microseconds, to use in a udelay(1) loop; I
dropped this in one place, but I left it in another, where the code
notes that it is "intentionally similar to do_write_oneword()".

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c | 41 +++++++++++++++++--------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 6c85f61..4e28081 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -754,7 +754,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 	struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
 
  resettime:
-	timeo = jiffies + HZ;
+	timeo = jiffies + msecs_to_jiffies(1000);
  retry:
 	switch (chip->state) {
 
@@ -1228,15 +1228,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long timeo;
 	/*
-	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices
-	 * have a max write time of a few hundreds usec). However, we should
-	 * use the maximum timeout value given by the chip at probe time
-	 * instead.  Unfortunately, struct flchip does have a field for
-	 * maximum timeout, only for typical which can be far too short
-	 * depending of the conditions.	 The ' + 1' is to avoid having a
-	 * timeout of 0 jiffies if HZ is smaller than 1000.
+	 * We use a 1ms generic timeout for writes (most devices have a max
+	 * write time of a few hundreds usec). However, we should use the
+	 * maximum timeout value given by the chip at probe time instead.
+	 * Unfortunately, struct flchip does have a field for maximum timeout,
+	 * only for typical which can be far too short depending of the
+	 * conditions.
 	 */
-	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+	unsigned long uWriteTimeout = msecs_to_jiffies(1);
 	int ret = 0;
 	map_word oldd;
 	int retry_cnt = 0;
@@ -1292,7 +1291,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 			mutex_unlock(&chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
-			timeo = jiffies + (HZ / 2); /* FIXME */
+			timeo = jiffies + msecs_to_jiffies(500); /* FIXME */
 			mutex_lock(&chip->mutex);
 			continue;
 		}
@@ -1465,8 +1464,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long timeo;
-	/* see comments in do_write_oneword() regarding uWriteTimeo. */
-	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+	/* see comments in do_write_oneword() regarding uWriteTimeout */
+	unsigned long uWriteTimeout = msecs_to_jiffies(1);
 	int ret = -EIO;
 	unsigned long cmd_adr;
 	int z, words;
@@ -1535,7 +1534,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 			mutex_unlock(&chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
-			timeo = jiffies + (HZ / 2); /* FIXME */
+			timeo = jiffies + msecs_to_jiffies(500); /* FIXME */
 			mutex_lock(&chip->mutex);
 			continue;
 		}
@@ -1687,13 +1686,11 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
 	 * is more important to save the messages.
 	 */
 	while (retries > 0) {
-		const unsigned long timeo = (HZ / 1000) + 1;
-
 		/* send the reset command */
 		map_write(map, CMD(0xF0), chip->start);
 
-		/* wait for the chip to become ready */
-		for (i = 0; i < jiffies_to_usecs(timeo); i++) {
+		/* wait for the chip to become ready (approx. 1ms) */
+		for (i = 0; i < 1000; i++) {
 			if (chip_ready(map, adr))
 				return 0;
 
@@ -1719,7 +1716,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
 static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
 				  unsigned long adr, map_word datum)
 {
-	const unsigned long uWriteTimeout = (HZ / 1000) + 1;
+	const unsigned long uWriteTimeout = msecs_to_jiffies(1);
 	struct cfi_private *cfi = map->fldrv_priv;
 	int retry_cnt = 0;
 	map_word oldd;
@@ -1934,7 +1931,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 				adr, map->size,
 				chip->erase_time*500);
 
-	timeo = jiffies + (HZ*20);
+	timeo = jiffies + msecs_to_jiffies(20000);
 
 	for (;;) {
 		if (chip->state != FL_ERASING) {
@@ -1950,7 +1947,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 		if (chip->erase_suspended) {
 			/* This erase was suspended and resumed.
 			   Adjust the timeout */
-			timeo = jiffies + (HZ*20); /* FIXME */
+			timeo = jiffies + msecs_to_jiffies(20000); /* FIXME */
 			chip->erase_suspended = 0;
 		}
 
@@ -2023,7 +2020,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 				adr, len,
 				chip->erase_time*500);
 
-	timeo = jiffies + (HZ*20);
+	timeo = jiffies + msecs_to_jiffies(20000);
 
 	for (;;) {
 		if (chip->state != FL_ERASING) {
@@ -2039,7 +2036,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 		if (chip->erase_suspended) {
 			/* This erase was suspended and resumed.
 			   Adjust the timeout */
-			timeo = jiffies + (HZ*20); /* FIXME */
+			timeo = jiffies + msecs_to_jiffies(20000); /* FIXME */
 			chip->erase_suspended = 0;
 		}
 
-- 
1.8.2.3



From computersforpeace at gmail.com  Mon Jun  3 21:46:46 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon,  3 Jun 2013 18:46:46 -0700
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer() timeout
In-Reply-To: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
Message-ID: <1370310406-413-3-git-send-email-computersforpeace@gmail.com>

I have seen various failures like this while doing a simple reboot +
mount UBIFS test:

  UBIFS: recovery needed
  MTD do_write_buffer(): software timeout
  UBI error: ubi_io_write: error -5 while writing 512 bytes to PEB 365:43648, written 192 bytes

(This message doens't exactly match the message in the current head of
tree, as Huang edited the timeout message.)

I'm using a 64Mbyte Spansion S29GL512 NOR flash. I've also seen reports
of the same failure on Micron 128Mbyte NOR flash AM29EWLD.

After various tests, it seems simply that the timeout is not long enough
for my system; increasing it by a few jiffies prevented all failures
(testing for 12+ hours). There is no harm in increasing the timeout, but
there is harm in having it too short, as evidenced here.

This patch increases the timeout value in 3 locations, as they all are
referencing the do_write_oneword function. I have only ever seen the
timeout in do_write_buffer().

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 4e28081..45de025 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1228,14 +1228,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long timeo;
 	/*
-	 * We use a 1ms generic timeout for writes (most devices have a max
-	 * write time of a few hundreds usec). However, we should use the
-	 * maximum timeout value given by the chip at probe time instead.
-	 * Unfortunately, struct flchip does have a field for maximum timeout,
-	 * only for typical which can be far too short depending of the
-	 * conditions.
+	 * We use a 10ms generic timeout for writes. Most devices have a max
+	 * write time of a few hundreds usec, but timeouts have been seen with
+	 * too few jiffies.
 	 */
-	unsigned long uWriteTimeout = msecs_to_jiffies(1);
+	unsigned long uWriteTimeout = msecs_to_jiffies(10);
 	int ret = 0;
 	map_word oldd;
 	int retry_cnt = 0;
@@ -1465,7 +1462,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long timeo;
 	/* see comments in do_write_oneword() regarding uWriteTimeout */
-	unsigned long uWriteTimeout = msecs_to_jiffies(1);
+	unsigned long uWriteTimeout = msecs_to_jiffies(10);
 	int ret = -EIO;
 	unsigned long cmd_adr;
 	int z, words;
@@ -1716,7 +1713,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
 static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
 				  unsigned long adr, map_word datum)
 {
-	const unsigned long uWriteTimeout = msecs_to_jiffies(1);
+	const unsigned long uWriteTimeout = msecs_to_jiffies(10);
 	struct cfi_private *cfi = map->fldrv_priv;
 	int retry_cnt = 0;
 	map_word oldd;
-- 
1.8.2.3



From b32955 at freescale.com  Tue Jun  4 03:03:28 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Tue, 4 Jun 2013 15:03:28 +0800
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer()
 timeout
In-Reply-To: <1370310406-413-3-git-send-email-computersforpeace@gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
 <1370310406-413-3-git-send-email-computersforpeace@gmail.com>
Message-ID: <51AD9140.90500@freescale.com>

? 2013?06?04? 09:46, Brian Norris ??:
> After various tests, it seems simply that the timeout is not long enough
> for my system; increasing it by a few jiffies prevented all failures
> (testing for 12+ hours). There is no harm in increasing the timeout, but
> there is harm in having it too short, as evidenced here.
>
I like the patch1 and patch 2.

But extending the timeout from 1ms to 10ms is like a workaround. :)

>From the NOR's spec, even the maximum write-to-buffer only costs several
hundreds us,
such as 200us.

I GUESS your problem is caused by the timer system, not the MTD code. I
ever met this type of bug.
The bug is in the kernel 3.5.7, but the latest kernel has fixed it with
NO_HZ_IDLE/NO_HZ_COMMON features.
I do not meet the issue the latest linux-next tree.

I try to describe the jiffies bug with my poor english:

[1] background:
CONFIG_HZ=100, CONFIG_NO_HZ=y

[2] call nand_wait() when we write a nand page.

[3] The jiffies was not updated at a _even_ speed.

In the nand_wait(), you wait for 20ms(2 jiffies) for a page write,
and the timeout occurs during the page write. Of course, you think that
we have already waited for 20ms.
But in actually, we only waited for 1ms or less!
How do i know this? I use the gettimeofday to check the real time when
the timeout occur.

[4] if i disable the local timer, the bug disappears.


So, could you check the real time when the timeout occurs?



Btw: My NOR's timeout is proved to be a silicon bug by Micron.

thanks
Huang Shijie






From christian.riesch at omicron.at  Tue Jun  4 07:30:50 2013
From: christian.riesch at omicron.at (Christian Riesch)
Date: Tue, 04 Jun 2013 13:30:50 +0200
Subject: [PATCH v2 1/4] mtd: cfi_cmdset_0002: Add support for reading OTP
In-Reply-To: <1370252414.21714.29.camel@sauron.fi.intel.com>
References: <1367003430-24584-1-git-send-email-christian.riesch@omicron.at>
 <38c84e40-1171-4040-bc8b-ec51a0485819@mary.at.omicron.at>
 <1369811482.5446.216.camel@sauron.fi.intel.com> <51A5FA84.8030906@omicron.at>
 <1369835589.24286.31.camel@sauron.fi.intel.com> <51A61274.70607@omicron.at>
 <1370252414.21714.29.camel@sauron.fi.intel.com>
Message-ID: <51ADCFEA.3060605@omicron.at>

On 2013-06-03 11:40, Artem Bityutskiy wrote:
> On Wed, 2013-05-29 at 16:36 +0200, Christian Riesch wrote:
>>> But retlen is where you return the amount of bytes you actually
>> wrote.
>>> The return code is either 0 or a negative error code number. This is
>>> what we do in mtd_write() and I'd expect the OTP functions to be
>>> consistent.
>>
>> Unlike mtd_write, mtd->_get_fact_prot_info (which is a pointer to
>> cfi_amdstd_get_fact_prot_info here) does not have a retlen parameter.
>> Do
>> you suggest to change this?
>
> Yes, I would suggest this.
>

Ok, I will prepare a patch for this.
Thanks, Christian


From sachin.kamat at linaro.org  Tue Jun  4 08:02:45 2013
From: sachin.kamat at linaro.org (Sachin Kamat)
Date: Tue, 4 Jun 2013 17:32:45 +0530
Subject: [PATCH 1/3] mtd: onenand/generic: Remove redundant
 platform_set_drvdata()
In-Reply-To: <1367581063-24295-1-git-send-email-sachin.kamat@linaro.org>
References: <1367581063-24295-1-git-send-email-sachin.kamat@linaro.org>
Message-ID: <CAK9yfHysGeinDQdVVMYs3j5Vb9cNGiMhtXg4TgOZTSHU5ZuN+Q@mail.gmail.com>

On 3 May 2013 17:07, Sachin Kamat <sachin.kamat at linaro.org> wrote:
> Commit 0998d06310 (device-core: Ensure drvdata = NULL when no
> driver is bound) removes the need to set driver data field to
> NULL.
>
> Signed-off-by: Sachin Kamat <sachin.kamat at linaro.org>
> Cc: Kyungmin Park <kyungmin.park at samsung.com>
> ---
>  drivers/mtd/onenand/generic.c |    2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
> index 9f11562..42520a3 100644
> --- a/drivers/mtd/onenand/generic.c
> +++ b/drivers/mtd/onenand/generic.c
> @@ -94,8 +94,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
>         struct resource *res = pdev->resource;
>         unsigned long size = resource_size(res);
>
> -       platform_set_drvdata(pdev, NULL);
> -
>         if (info) {
>                 onenand_release(&info->mtd);
>                 release_mem_region(res->start, size);
> --
> 1.7.9.5
>


Ping on this series.


-- 
With warm regards,
Sachin


From elezegarcia at gmail.com  Tue Jun  4 10:41:39 2013
From: elezegarcia at gmail.com (Ezequiel Garcia)
Date: Tue, 4 Jun 2013 11:41:39 -0300
Subject: [PATCH v3 1/1] ubi: Introduce block devices for UBI volumes
In-Reply-To: <1368887515-10536-2-git-send-email-ezequiel.garcia@free-electrons.com>
References: <1368887515-10536-1-git-send-email-ezequiel.garcia@free-electrons.com>
 <1368887515-10536-2-git-send-email-ezequiel.garcia@free-electrons.com>
Message-ID: <CALF0-+UMTK0jCOXqvR7LAHSFbqsFTgh8kh-wtT=FctrcHtbD_A@mail.gmail.com>

Hi Artem,

On Sat, May 18, 2013 at 11:31 AM, Ezequiel Garcia
<ezequiel.garcia at free-electrons.com> wrote:
> Block device emulation on top of ubi volumes with read/write support.
>
> Given UBI takes care of wear leveling and bad block management it's possible
> to add a thin layer to enable block device access to UBI volumes.
> This allows to use a block-oriented filesystem on a flash device.
>
> In a similar fashion to mtdblock, two 1-LEB size caches have been implemented:
> one for reading and one for writing.
>
> Every read and every write goes through one of these caches.
> Read requests can be satisfied through the read cache or the write cache.
> Write requests always fill the write cache (possibly flushing it).
> This fill is done through the read cache, if this is possible.
> If the requested leb is not cached, it's loaded to the associated cache.
>
> The flash device is written when the write cache is flushed on:
> * block device release (detach)
> * a different than cached leb is accessed
> * io-barrier is received through a REQ_FLUSH request
>
> By creating two caches we decouple read access from write access,
> in an effort to improve wear leveling.
>
> Despite this efforts, it's very important to remember that regular
> block-oriented filesystems have no care at all about wear leveling;
> they will access the block device randomly, only caring for performance.
> Therefore, write support should be selected only for development and
> with extreme caution.
>
> Both caches are 1-LEB bytes, vmalloced at open() and freed at release();
> in addition, each block device has a workqueue associated.
>
> Block devices are created upon user request through new ioctls:
> UBI_IOCVOLATTBLK to attach and UBI_IOCVOLDETBLK to detach.
> Also, a new UBI module parameter is added 'ubi.block'. This parameter is
> needed in order to attach a block device on boot-up time, allowing to
> mount the rootfs on a ubiblock device.
> For instance, you could have these kernel parameters:
>
>   ubi.mtd=5 ubi.block=0,0 root=/dev/ubiblock0_0
>
> Or, if you compile ubi as a module:
>
>   $ modprobe ubi mtd=/dev/mtd5 block=/dev/ubi0_0
>
> Cc: Mike Frysinger <vapier at gentoo.org>
> Signed-off-by: Ezequiel Garcia <ezequiel.garcia at free-electrons.com>
> ---
>  drivers/mtd/ubi/Kconfig     |  24 ++
>  drivers/mtd/ubi/Makefile    |   1 +
>  drivers/mtd/ubi/block.c     | 894 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/ubi/build.c     |   5 +
>  drivers/mtd/ubi/cdev.c      |  20 +
>  drivers/mtd/ubi/ubi.h       |  14 +
>  include/uapi/mtd/ubi-user.h |  11 +
>  7 files changed, 969 insertions(+)
>  create mode 100644 drivers/mtd/ubi/block.c
>

Any feedback for this?

There were several users asking for this kind of UBI block support
(Mike Frysinger being among the most recent).

So if there are no objections, and given the patch is not really intrusive
on the UBI core, I think it's safe to merge it.

-- 
    Ezequiel


From joe at perches.com  Tue Jun  4 10:44:49 2013
From: joe at perches.com (Joe Perches)
Date: Tue,  4 Jun 2013 07:44:49 -0700
Subject: [PATCH 3/4] mtd: onenand: samsung: Release memory after incorrect
 return/goto
In-Reply-To: <60123fd3175b7cceadf6c335b12e58b797e18f65.1370356776.git.joe@perches.com>
References: <60123fd3175b7cceadf6c335b12e58b797e18f65.1370356776.git.joe@perches.com>
Message-ID: <ec732a1673510a786e5333b00730b8226e792357.1370356776.git.joe@perches.com>

The code uses

    return foo;
    goto err_type;

when instead the form should have been

    ret = foo;
    goto err_type;

Here this causes a useful kfree to be skipped.

Signed-off-by: Joe Perches <joe at perches.com>
---
 drivers/mtd/onenand/samsung.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index 2cf7408..90bd111 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -895,8 +895,8 @@ static int s3c_onenand_probe(struct platform_device *pdev)
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r) {
 		dev_err(&pdev->dev, "no memory resource defined\n");
-		return -ENOENT;
-		goto ahb_resource_failed;
+		err = -ENOENT;
+		goto resource_failed;
 	}
 
 	onenand->base_res = request_mem_region(r->start, resource_size(r),
-- 
1.8.1.2.459.gbcd45b4.dirty



From peter.crosthwaite at xilinx.com  Wed Jun  5 01:57:59 2013
From: peter.crosthwaite at xilinx.com (Peter Crosthwaite)
Date: Wed, 5 Jun 2013 15:57:59 +1000
Subject: [RFC] Micron M25P80 Part name variants
Message-ID: <CAEgOgz6jjh9-G6PmzrjJcG7LKCnh4cAooSnCiZ9cmz_qUs8AXg@mail.gmail.com>

Hi All,

For micron M25P80 parts there is a mix of naming conventions in the
device table:

        /* Micron */
        { "n25q064",  INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
        { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
        { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
        { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },

n25q128 has a11 and a13 variants, while 256 does not. Should this be
consistent across parts? If so should we adopt Liming Wangs "axx"
precedent universally? Here is a hunk from Ed Maste that applies the
relevant change to QEMU (currently on list) that would be nice to
merge. Can we fix this Linux side in similar fashion?

     /* Micron */
-    { INFO("n25q032a",    0x20bb16,      0,  64 << 10,  64, ER_4K) },
-    { INFO("n25q128a11",  0x20bb18,      0,  64 << 10, 256, 0) },
-    { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, 0) },
-    { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512, ER_4K) },
+    { INFO("n25q032a11",  0x20bb16,      0,  64 << 10,  64, ER_4K) },
+    { INFO("n25q032a13",  0x20ba16,      0,  64 << 10,  64, ER_4K) },
+    { INFO("n25q064a11",  0x20bb17,      0,  64 << 10, 128, ER_4K) },
+    { INFO("n25q064a13",  0x20ba17,      0,  64 << 10, 128, ER_4K) },
+    { INFO("n25q128a11",  0x20bb18,      0,  64 << 10, 256, ER_4K) },
+    { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, ER_4K) },
+    { INFO("n25q256a11",  0x20bb19,      0,  64 << 10, 512, ER_4K) },
+    { INFO("n25q256a13",  0x20ba19,      0,  64 << 10, 512, ER_4K) },

Regards,
Peter


From pekon at ti.com  Wed Jun  5 03:01:32 2013
From: pekon at ti.com (Gupta, Pekon)
Date: Wed, 5 Jun 2013 07:01:32 +0000
Subject: [PATCH 20/26] mtd: nand: omap2: remove unnecessary
 platform_set_drvdata()
In-Reply-To: <005801ce4aed$ed90d6c0$c8b28440$@samsung.com>
References: <005801ce4aed$ed90d6c0$c8b28440$@samsung.com>
Message-ID: <20980858CB6D3A4BAE95CA194937D5E73E9D978A@DBDE04.ent.ti.com>

> The driver core clears the driver data to NULL after device_release
> or on probe failure, since commit
> 0998d0631001288a5974afc0b2a5f568bcdecb4d
> (device-core: Ensure drvdata = NULL when no driver is bound).
> Thus, it is not needed to manually clear the device driver data to NULL.
> 
> Signed-off-by: Jingoo Han <jg1.han at samsung.com>
Acked-by: Pekon Gupta <pekon at ti.com>

Thanks for this .. 
With regards, pekon

> ---
>  drivers/mtd/nand/omap2.c |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index 81b80af..daa3dfc 100644
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -2087,7 +2087,6 @@ static int omap_nand_remove(struct
> platform_device *pdev)
>  							mtd);
>  	omap3_free_bch(&info->mtd);
> 
> -	platform_set_drvdata(pdev, NULL);
>  	if (info->dma)
>  		dma_release_channel(info->dma);
> 
> --
> 1.7.2.5
> 
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From dedekind1 at gmail.com  Wed Jun  5 11:24:27 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Wed, 05 Jun 2013 18:24:27 +0300
Subject: UBIFS: Orphaned inode 1
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8C034@post.tritech.se>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FC8BF32@post.tritech.se>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8C034@post.tritech.se>
Message-ID: <1370445867.2938.1.camel@sauron.fi.intel.com>

On Mon, 2013-06-03 at 13:03 +0000, Mats K?rrman wrote:
> Hi,
> 
> I'm facing a problem involving systems running in the field that suddenly cannot
> boot anymore because the root UBIFS file system residing in a NOR flash
> cannot be mounted. Error msg in kernel log is:
> 
> UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
> 
> I have managed to copy a failing FLASH image into a file on my PC, uploaded it
> to an mtdram device and tried to mount it with all debug info turned on and
> "general" checks enabled. The final error is the same:
> 
> < snip >
> [ 5513.523872] UBIFS: mounted UBI device 0, volume 0, name "debug-rootfs"
> [ 5513.523878] UBIFS: file system size:   57877248 bytes (56520 KiB, 55 MiB, 442 LEBs)
> [ 5513.523882] UBIFS: journal size:       8773248 bytes (8567 KiB, 8 MiB, 67 LEBs)
> [ 5513.523885] UBIFS: media format:       w4/r0 (latest is w4/r0)
> [ 5513.523887] UBIFS: default compressor: lzo
> [ 5513.523893] UBIFS: reserved for root:  261902 bytes (255 KiB)
> [ 5513.523896] UBIFS DBG (pid 4659): mount_ubifs: compiled on:         May 31 2013 at 13:31:25
> [ 5513.523900] UBIFS DBG (pid 4659): mount_ubifs: min. I/O unit size:  8 bytes
> [ 5513.523903] UBIFS DBG (pid 4659): mount_ubifs: max. write size:     64 bytes
> [ 5513.523905] UBIFS DBG (pid 4659): mount_ubifs: LEB size:            130944 bytes (127 KiB)
> [ 5513.523908] UBIFS DBG (pid 4659): mount_ubifs: data journal heads:  1
> [ 5513.523911] UBIFS DBG (pid 4659): mount_ubifs: UUID:                B43E1323-1747-41FB-9C11-F4C0E59C24B8
> [ 5513.523914] UBIFS DBG (pid 4659): mount_ubifs: big_lpt              0
> [ 5513.523916] UBIFS DBG (pid 4659): mount_ubifs: log LEBs:            4 (3 - 6)
> [ 5513.523919] UBIFS DBG (pid 4659): mount_ubifs: LPT area LEBs:       2 (7 - 8)
> [ 5513.523921] UBIFS DBG (pid 4659): mount_ubifs: orphan area LEBs:    1 (9 - 9)
> [ 5513.523924] UBIFS DBG (pid 4659): mount_ubifs: main area LEBs:      442 (10 - 451)
> [ 5513.523926] UBIFS DBG (pid 4659): mount_ubifs: index LEBs:          32
> [ 5513.523935] UBIFS DBG (pid 4659): mount_ubifs: total index bytes:   622720 (608 KiB, 0 MiB)
> [ 5513.523940] UBIFS DBG (pid 4659): mount_ubifs: key hash type:       0
> [ 5513.523944] UBIFS DBG (pid 4659): mount_ubifs: tree fanout:         8
> [ 5513.523949] UBIFS DBG (pid 4659): mount_ubifs: reserved GC LEB:     443
> [ 5513.523953] UBIFS DBG (pid 4659): mount_ubifs: first main LEB:      10
> [ 5513.523958] UBIFS DBG (pid 4659): mount_ubifs: max. znode size      320
> [ 5513.523964] UBIFS DBG (pid 4659): mount_ubifs: max. index node size 192
> [ 5513.523967] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          data 48, inode 160, dentry 56
> [ 5513.523970] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          trun 56, sb 4096, master 512
> [ 5513.523973] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          ref 64, cmt. start 32, orph 32
> [ 5513.523977] UBIFS DBG (pid 4659): mount_ubifs: max. node sizes:     data 4144, inode 4256 dentry 312, idx 188
> [ 5513.523979] UBIFS DBG (pid 4659): mount_ubifs: dead watermark:      56
> [ 5513.523982] UBIFS DBG (pid 4659): mount_ubifs: dark watermark:      4256
> [ 5513.523984] UBIFS DBG (pid 4659): mount_ubifs: LEB overhead:        2480
> [ 5513.523987] UBIFS DBG (pid 4659): mount_ubifs: max. dark space:     1881152 (1837 KiB, 1 MiB)
> [ 5513.523989] UBIFS DBG (pid 4659): mount_ubifs: maximum bud bytes:   8249472 (8056 KiB, 7 MiB)
> [ 5513.523992] UBIFS DBG (pid 4659): mount_ubifs: BG commit bud bytes: 6702696 (6545 KiB, 6 MiB)
> [ 5513.523995] UBIFS DBG (pid 4659): mount_ubifs: current bud bytes    90112 (88 KiB, 0 MiB)
> [ 5513.523998] UBIFS DBG (pid 4659): mount_ubifs: max. seq. number:    23851433
> [ 5513.524000] UBIFS DBG (pid 4659): mount_ubifs: commit number:       1769
> [ 5513.524003] ubifs_iget: UBIFS DBG gen: inode 1
> [ 5513.524011] ubifs_lookup_level0: UBIFS DBG tnc: search key (1, inode)
> [ 5513.524015] ubifs_lookup_level0: UBIFS DBG tnc: found 0, lvl 0, n -1
> [ 5513.524018] UBIFS error (pid 4659): ubifs_iget: failed to read inode 1, error -2
> [ 5513.524022] ubifs_evict_inode: UBIFS DBG gen: inode 1, mode 0x8000
> [ 5513.524026] ubifs_umount: UBIFS DBG gen: un-mounting UBI device 0, volume 0
> [ 5513.524049] UBIFS DBG (pid 4660): ubifs_bg_thread: background thread "ubifs_bgt0_0" stops
> 
> If i grep the log for recovery messages I get:
> 
> [ 5513.520324] UBIFS: recovery needed
> [ 5513.520327] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking index head at 449:109136
> [ 5513.520343] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking LPT head at 7:123208
> [ 5513.520983] ubifs_recover_leb: UBIFS DBG rcvry: 219:93032, jhead 0, grouped 0
> [ 5513.521039] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
> [ 5513.521073] clean_buf: UBIFS DBG rcvry: cleaning corruption at 219:93032
> [ 5513.521079] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 219 start 93032 endpt 93032
> [ 5513.521396] ubifs_recover_leb: UBIFS DBG rcvry: 369:83568, jhead 1, grouped 1
> [ 5513.521474] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
> [ 5513.521548] clean_buf: UBIFS DBG rcvry: cleaning corruption at 369:83568
> [ 5513.521557] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 369 start 83568 endpt 83568
> [ 5513.521853] ubifs_recover_leb: UBIFS DBG rcvry: 444:126120, jhead 2, grouped 1
> [ 5513.521919] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
> [ 5513.521952] clean_buf: UBIFS DBG rcvry: cleaning corruption at 444:126120
> [ 5513.521968] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 444 start 126120 endpt 126120
> [ 5513.522770] kill_orphans: UBIFS DBG rcvry: LEB 9
> [ 5513.522885] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1208852
> [ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1
> [ 5513.523489] do_kill_orphans: UBIFS DBG rcvry: last orph node for commit 1700 at 9:0
> [ 5513.523494] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC head LEB 219, offs 93032
> [ 5513.523512] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: committing
> [ 5513.523768] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC'ing LEB 443
> [ 5513.523840] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: allocated LEB 443 for GC
> [ 5513.523843] UBIFS: recovery completed
> 
> The message that caught my attention:
> 
> [ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1
> 
> How can inode 1 be an orphan, or rather shouldn't it be?
> Is it possible for a user-space application to cause this error?
> Should I also look in UBI and MTD layers for the cause?
> I'm not sure where to go on from here, any suggestions are welcome!!
> 
> My target system runs a Freescale MPC5125 (PPC e300c4) with a Linux 2.6.35.14
> kernel patched with all UBFS patches from Artem's 2.6.35 maintenance tree and
> additional ones from later kernel versions.
> My PC runs the latest LMDE (3.2.32) recompiled with dynamic debug turned on.

You are the second person reporting this for 2.6.35. Probably I
introduced a bug while back-porting stuff.

Can you reproduce this or try to find a way to reproduce?

Can you share your image?


-- 
Best Regards,
Artem Bityutskiy



From motobud at gmail.com  Wed Jun  5 11:40:32 2013
From: motobud at gmail.com (Brent Taylor)
Date: Wed, 5 Jun 2013 10:40:32 -0500
Subject: UBIFS: Orphaned inode 1
In-Reply-To: <1370445867.2938.1.camel@sauron.fi.intel.com>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FC8BF32@post.tritech.se>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8C034@post.tritech.se>
 <1370445867.2938.1.camel@sauron.fi.intel.com>
Message-ID: <CAP+RiCBQNsXN0eTfrX90wZm17oHR6h=7EF6eUY9jJJ9Bfjc7og@mail.gmail.com>

Artem,
   I've seen the same issue with 3.6.9.  I can get it to occur by
following these steps:
   1.  Flash an image generated by ubinize.
   2.  Boot the system to run first time initialization scripts (UBI
and UBIFS successfully mount the root filesystem).
   3.  Once initialization is complete, the system invokes 'sync' then
causes a kernel panic to reboot the system.
   4.  On the second (and subsequent boots) the problem is observed.

I've used 3.5.1 in the past without any issues so maybe something was
introduced between those versions.

-- Brent Taylor

On Wed, Jun 5, 2013 at 10:24 AM, Artem Bityutskiy <dedekind1 at gmail.com> wrote:
> On Mon, 2013-06-03 at 13:03 +0000, Mats K?rrman wrote:
>> Hi,
>>
>> I'm facing a problem involving systems running in the field that suddenly cannot
>> boot anymore because the root UBIFS file system residing in a NOR flash
>> cannot be mounted. Error msg in kernel log is:
>>
>> UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
>>
>> I have managed to copy a failing FLASH image into a file on my PC, uploaded it
>> to an mtdram device and tried to mount it with all debug info turned on and
>> "general" checks enabled. The final error is the same:
>>
>> < snip >
>> [ 5513.523872] UBIFS: mounted UBI device 0, volume 0, name "debug-rootfs"
>> [ 5513.523878] UBIFS: file system size:   57877248 bytes (56520 KiB, 55 MiB, 442 LEBs)
>> [ 5513.523882] UBIFS: journal size:       8773248 bytes (8567 KiB, 8 MiB, 67 LEBs)
>> [ 5513.523885] UBIFS: media format:       w4/r0 (latest is w4/r0)
>> [ 5513.523887] UBIFS: default compressor: lzo
>> [ 5513.523893] UBIFS: reserved for root:  261902 bytes (255 KiB)
>> [ 5513.523896] UBIFS DBG (pid 4659): mount_ubifs: compiled on:         May 31 2013 at 13:31:25
>> [ 5513.523900] UBIFS DBG (pid 4659): mount_ubifs: min. I/O unit size:  8 bytes
>> [ 5513.523903] UBIFS DBG (pid 4659): mount_ubifs: max. write size:     64 bytes
>> [ 5513.523905] UBIFS DBG (pid 4659): mount_ubifs: LEB size:            130944 bytes (127 KiB)
>> [ 5513.523908] UBIFS DBG (pid 4659): mount_ubifs: data journal heads:  1
>> [ 5513.523911] UBIFS DBG (pid 4659): mount_ubifs: UUID:                B43E1323-1747-41FB-9C11-F4C0E59C24B8
>> [ 5513.523914] UBIFS DBG (pid 4659): mount_ubifs: big_lpt              0
>> [ 5513.523916] UBIFS DBG (pid 4659): mount_ubifs: log LEBs:            4 (3 - 6)
>> [ 5513.523919] UBIFS DBG (pid 4659): mount_ubifs: LPT area LEBs:       2 (7 - 8)
>> [ 5513.523921] UBIFS DBG (pid 4659): mount_ubifs: orphan area LEBs:    1 (9 - 9)
>> [ 5513.523924] UBIFS DBG (pid 4659): mount_ubifs: main area LEBs:      442 (10 - 451)
>> [ 5513.523926] UBIFS DBG (pid 4659): mount_ubifs: index LEBs:          32
>> [ 5513.523935] UBIFS DBG (pid 4659): mount_ubifs: total index bytes:   622720 (608 KiB, 0 MiB)
>> [ 5513.523940] UBIFS DBG (pid 4659): mount_ubifs: key hash type:       0
>> [ 5513.523944] UBIFS DBG (pid 4659): mount_ubifs: tree fanout:         8
>> [ 5513.523949] UBIFS DBG (pid 4659): mount_ubifs: reserved GC LEB:     443
>> [ 5513.523953] UBIFS DBG (pid 4659): mount_ubifs: first main LEB:      10
>> [ 5513.523958] UBIFS DBG (pid 4659): mount_ubifs: max. znode size      320
>> [ 5513.523964] UBIFS DBG (pid 4659): mount_ubifs: max. index node size 192
>> [ 5513.523967] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          data 48, inode 160, dentry 56
>> [ 5513.523970] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          trun 56, sb 4096, master 512
>> [ 5513.523973] UBIFS DBG (pid 4659): mount_ubifs: node sizes:          ref 64, cmt. start 32, orph 32
>> [ 5513.523977] UBIFS DBG (pid 4659): mount_ubifs: max. node sizes:     data 4144, inode 4256 dentry 312, idx 188
>> [ 5513.523979] UBIFS DBG (pid 4659): mount_ubifs: dead watermark:      56
>> [ 5513.523982] UBIFS DBG (pid 4659): mount_ubifs: dark watermark:      4256
>> [ 5513.523984] UBIFS DBG (pid 4659): mount_ubifs: LEB overhead:        2480
>> [ 5513.523987] UBIFS DBG (pid 4659): mount_ubifs: max. dark space:     1881152 (1837 KiB, 1 MiB)
>> [ 5513.523989] UBIFS DBG (pid 4659): mount_ubifs: maximum bud bytes:   8249472 (8056 KiB, 7 MiB)
>> [ 5513.523992] UBIFS DBG (pid 4659): mount_ubifs: BG commit bud bytes: 6702696 (6545 KiB, 6 MiB)
>> [ 5513.523995] UBIFS DBG (pid 4659): mount_ubifs: current bud bytes    90112 (88 KiB, 0 MiB)
>> [ 5513.523998] UBIFS DBG (pid 4659): mount_ubifs: max. seq. number:    23851433
>> [ 5513.524000] UBIFS DBG (pid 4659): mount_ubifs: commit number:       1769
>> [ 5513.524003] ubifs_iget: UBIFS DBG gen: inode 1
>> [ 5513.524011] ubifs_lookup_level0: UBIFS DBG tnc: search key (1, inode)
>> [ 5513.524015] ubifs_lookup_level0: UBIFS DBG tnc: found 0, lvl 0, n -1
>> [ 5513.524018] UBIFS error (pid 4659): ubifs_iget: failed to read inode 1, error -2
>> [ 5513.524022] ubifs_evict_inode: UBIFS DBG gen: inode 1, mode 0x8000
>> [ 5513.524026] ubifs_umount: UBIFS DBG gen: un-mounting UBI device 0, volume 0
>> [ 5513.524049] UBIFS DBG (pid 4660): ubifs_bg_thread: background thread "ubifs_bgt0_0" stops
>>
>> If i grep the log for recovery messages I get:
>>
>> [ 5513.520324] UBIFS: recovery needed
>> [ 5513.520327] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking index head at 449:109136
>> [ 5513.520343] ubifs_recover_inl_heads: UBIFS DBG rcvry: checking LPT head at 7:123208
>> [ 5513.520983] ubifs_recover_leb: UBIFS DBG rcvry: 219:93032, jhead 0, grouped 0
>> [ 5513.521039] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
>> [ 5513.521073] clean_buf: UBIFS DBG rcvry: cleaning corruption at 219:93032
>> [ 5513.521079] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 219 start 93032 endpt 93032
>> [ 5513.521396] ubifs_recover_leb: UBIFS DBG rcvry: 369:83568, jhead 1, grouped 1
>> [ 5513.521474] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
>> [ 5513.521548] clean_buf: UBIFS DBG rcvry: cleaning corruption at 369:83568
>> [ 5513.521557] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 369 start 83568 endpt 83568
>> [ 5513.521853] ubifs_recover_leb: UBIFS DBG rcvry: 444:126120, jhead 2, grouped 1
>> [ 5513.521919] ubifs_recover_leb: UBIFS DBG rcvry: found corruption - -1
>> [ 5513.521952] clean_buf: UBIFS DBG rcvry: cleaning corruption at 444:126120
>> [ 5513.521968] fix_unclean_leb: UBIFS DBG rcvry: fixing LEB 444 start 126120 endpt 126120
>> [ 5513.522770] kill_orphans: UBIFS DBG rcvry: LEB 9
>> [ 5513.522885] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1208852
>> [ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1
>> [ 5513.523489] do_kill_orphans: UBIFS DBG rcvry: last orph node for commit 1700 at 9:0
>> [ 5513.523494] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC head LEB 219, offs 93032
>> [ 5513.523512] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: committing
>> [ 5513.523768] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: GC'ing LEB 443
>> [ 5513.523840] ubifs_rcvry_gc_commit: UBIFS DBG rcvry: allocated LEB 443 for GC
>> [ 5513.523843] UBIFS: recovery completed
>>
>> The message that caught my attention:
>>
>> [ 5513.523313] do_kill_orphans: UBIFS DBG rcvry: deleting orphaned inode 1
>>
>> How can inode 1 be an orphan, or rather shouldn't it be?
>> Is it possible for a user-space application to cause this error?
>> Should I also look in UBI and MTD layers for the cause?
>> I'm not sure where to go on from here, any suggestions are welcome!!
>>
>> My target system runs a Freescale MPC5125 (PPC e300c4) with a Linux 2.6.35.14
>> kernel patched with all UBFS patches from Artem's 2.6.35 maintenance tree and
>> additional ones from later kernel versions.
>> My PC runs the latest LMDE (3.2.32) recompiled with dynamic debug turned on.
>
> You are the second person reporting this for 2.6.35. Probably I
> introduced a bug while back-porting stuff.
>
> Can you reproduce this or try to find a way to reproduce?
>
> Can you share your image?
>
>
> --
> Best Regards,
> Artem Bityutskiy
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


From dedekind1 at gmail.com  Wed Jun  5 11:47:31 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Wed, 05 Jun 2013 18:47:31 +0300
Subject: UBIFS: Orphaned inode 1
In-Reply-To: <CAP+RiCBQNsXN0eTfrX90wZm17oHR6h=7EF6eUY9jJJ9Bfjc7og@mail.gmail.com>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FC8BF32@post.tritech.se>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8C034@post.tritech.se>
 <1370445867.2938.1.camel@sauron.fi.intel.com>
 <CAP+RiCBQNsXN0eTfrX90wZm17oHR6h=7EF6eUY9jJJ9Bfjc7og@mail.gmail.com>
Message-ID: <1370447251.2938.19.camel@sauron.fi.intel.com>

On Wed, 2013-06-05 at 10:40 -0500, Brent Taylor wrote:
> Artem,
>    I've seen the same issue with 3.6.9.  I can get it to occur by
> following these steps:
>    1.  Flash an image generated by ubinize.
>    2.  Boot the system to run first time initialization scripts (UBI
> and UBIFS successfully mount the root filesystem).
>    3.  Once initialization is complete, the system invokes 'sync' then
> causes a kernel panic to reboot the system.
>    4.  On the second (and subsequent boots) the problem is observed.
> 
> I've used 3.5.1 in the past without any issues so maybe something was
> introduced between those versions.

If you guys could reproduce this, then this could become bisectable. 

Alternative is... I really have no time now, but if someone sends me the
faulty image, I can take a look later. No guarantees that I'll find
anything, because most probably I will only see the consequences of the
bug, not the root-cause. But I may come up with a theory at least.

-- 
Best Regards,
Artem Bityutskiy



From computersforpeace at gmail.com  Wed Jun  5 14:01:53 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Wed, 5 Jun 2013 11:01:53 -0700
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer()
 timeout
In-Reply-To: <51AD9140.90500@freescale.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
 <1370310406-413-3-git-send-email-computersforpeace@gmail.com>
 <51AD9140.90500@freescale.com>
Message-ID: <CAN8TOE9UDGuQd9AbE-4UVcAiqCFpqhY=fX+LbrDybdgr16THdQ@mail.gmail.com>

On Tue, Jun 4, 2013 at 12:03 AM, Huang Shijie <b32955 at freescale.com> wrote:
> ? 2013?06?04? 09:46, Brian Norris ??:
>> After various tests, it seems simply that the timeout is not long enough
>> for my system; increasing it by a few jiffies prevented all failures
>> (testing for 12+ hours). There is no harm in increasing the timeout, but
>> there is harm in having it too short, as evidenced here.
>>
> I like the patch1 and patch 2.
>
> But extending the timeout from 1ms to 10ms is like a workaround. :)

I was afraid you might say that; that's why I stuck the first two
patches first ;)

> From the NOR's spec, even the maximum write-to-buffer only costs several
> hundreds us,
> such as 200us.
>
> I GUESS your problem is caused by the timer system, not the MTD code. I
> ever met this type of bug.

I suspected similarly, but I didn't (until now) believe that's the
case here. See below.

> The bug is in the kernel 3.5.7, but the latest kernel has fixed it with
> NO_HZ_IDLE/NO_HZ_COMMON features.

Did you track your bug down to a particular commit? 3.5.7 is the
stable kernel; do you know what mainline rev it showed up in? I'm not
quite interested in backporting all of the new 3.10 features!

> I do not meet the issue the latest linux-next tree.
>
> I try to describe the jiffies bug with my poor english:
>
> [1] background:
> CONFIG_HZ=100, CONFIG_NO_HZ=y
>
> [2] call nand_wait() when we write a nand page.
>
> [3] The jiffies was not updated at a _even_ speed.
>
> In the nand_wait(), you wait for 20ms(2 jiffies) for a page write,
> and the timeout occurs during the page write. Of course, you think that
> we have already waited for 20ms.
> But in actually, we only waited for 1ms or less!
> How do i know this? I use the gettimeofday to check the real time when
> the timeout occur.

I suspected this very type of thing, since this has come up in a few
different contexts. And for some time, with a number of different
checks, it appeared that this *wasn't* the case. But while writing
this very email, I had the bright idea that my time checkpoint was in
slightly the wrong place; so sure enough, I found that I was timing
out after only 72519 ns! (That is, 72 us, or well below the max write
buffer time.)

I'm testing on MIPS with a 3.3 kernel, by the way, but I believe this
sort of bug has been around a while.

> [4] if i disable the local timer, the bug disappears.
>
> So, could you check the real time when the timeout occurs?
>
>
>
> Btw: My NOR's timeout is proved to be a silicon bug by Micron.

Interesting.

Brian


From benoit.thebaudeau at advansee.com  Wed Jun  5 14:37:58 2013
From: benoit.thebaudeau at advansee.com (=?utf-8?Q?Beno=C3=AEt_Th=C3=A9baudeau?=)
Date: Wed, 5 Jun 2013 20:37:58 +0200 (CEST)
Subject: UBI fastmap updates
In-Reply-To: <1476912797.1693715.1370457082122.JavaMail.root@advansee.com>
Message-ID: <2099899784.1693830.1370457478398.JavaMail.root@advansee.com>

Dear Artem Bityutskiy,

On Fri Aug 3 04:47:17 EDT 2012, Artem Bityutskiy wrote:
> On Mon, 2012-07-09 at 14:18 +0200, Richard Weinberger wrote:
> > This is the next round of UBI fastmap updates.
> > It fixes all issues pointed out by Shmulik. :-)
> > 
> > If you want to test fastmap you can use my git repo:
> > git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubi2.git ubi2/v17
> 
> Richard,
> 
> I've added 'stress-test.sh' script to the UBI tests. This script runs
> UBI tests on nandsim of different geometry. I plan to extend it
> further: add mtdram tests, test with bit-flips emulation enabled, may
> be something else.
> 
> We need to make sure all the tests pass and fastmap does not introduce
> regressions.
> 
> Feel free to send patches. I am going to extend the test today, so
> 'git pull' from time to time.
> 
> The tests will run very long time, so for debugging you can always
> comment out unneeded things.
> 
> ATM, I have only nandsim tests with different geometry: 64MiB to 1GiB
> total size, 2KiB and 512 byte pages, 16-256KiB eraseblocks.
> 
> Currently I am running this to unpatched UBI to check if they really
> pass.
> 
> I tried to run it on the patched UBI and hit this issue:
> 
> ======================================================================
> 16MiB nandsim with 16KiB PEB, 512KiB NAND pages, fastmap enabled
> Loaded NAND simulator (16MiB, 16KiB eraseblock, 512 bytes NAND page)
> Running mkvol_basic /dev/ubi0
> Running mkvol_bad /dev/ubi0
> Running mkvol_paral /dev/ubi0
> Running rsvol /dev/ubi0
> Running io_basic /dev/ubi0
> [io_basic] test_basic():70: function write() failed with error 28 (No
> space left on device)
> [io_basic] test_basic():70: written = 15808000, ret = -1
> Error: io_basic failed
> FAILURE
> ======================================================================
> 
> On non-patched UBI it works. I think it is exactly what I was talking
> about yesterday - fastmap grows unexpectedly because you do not
> reserve the space.

I am having the same issue on Ubuntu 13.04 with UBI on nandsim. See my bug
report here:
https://bugs.launchpad.net/bugs/1187885

What is the status for this issue on your side as of now?

Thanks in advance for your help.

Best regards,
Beno?t


From computersforpeace at gmail.com  Wed Jun  5 17:08:17 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Wed, 5 Jun 2013 14:08:17 -0700
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer()
 timeout
In-Reply-To: <CAN8TOE9UDGuQd9AbE-4UVcAiqCFpqhY=fX+LbrDybdgr16THdQ@mail.gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
 <1370310406-413-3-git-send-email-computersforpeace@gmail.com>
 <51AD9140.90500@freescale.com>
 <CAN8TOE9UDGuQd9AbE-4UVcAiqCFpqhY=fX+LbrDybdgr16THdQ@mail.gmail.com>
Message-ID: <CAN8TOE8FRtQupXwvAtrVSN-C-nQz-XgOW7OA5C=XRs9YmCwTkg@mail.gmail.com>

Adding a few others

For reference, this thread started with this patch:

http://lists.infradead.org/pipermail/linux-mtd/2013-June/047164.html

On Wed, Jun 5, 2013 at 11:01 AM, Brian Norris
<computersforpeace at gmail.com> wrote:
> On Tue, Jun 4, 2013 at 12:03 AM, Huang Shijie <b32955 at freescale.com> wrote:
>> ? 2013?06?04? 09:46, Brian Norris ??:
>>> After various tests, it seems simply that the timeout is not long enough
>>> for my system; increasing it by a few jiffies prevented all failures
>>> (testing for 12+ hours). There is no harm in increasing the timeout, but
>>> there is harm in having it too short, as evidenced here.
>>>
>> I like the patch1 and patch 2.
>>
>> But extending the timeout from 1ms to 10ms is like a workaround. :)
>
> I was afraid you might say that; that's why I stuck the first two
> patches first ;)
...
>> I GUESS your problem is caused by the timer system, not the MTD code. I
>> ever met this type of bug.
...
>> I try to describe the jiffies bug with my poor english:
>>
>> [1] background:
>> CONFIG_HZ=100, CONFIG_NO_HZ=y
>>
>> [2] call nand_wait() when we write a nand page.
>>
>> [3] The jiffies was not updated at a _even_ speed.
>>
>> In the nand_wait(), you wait for 20ms(2 jiffies) for a page write,
>> and the timeout occurs during the page write. Of course, you think that
>> we have already waited for 20ms.
>> But in actually, we only waited for 1ms or less!
>> How do i know this? I use the gettimeofday to check the real time when
>> the timeout occur.
>
> I suspected this very type of thing, since this has come up in a few
> different contexts. And for some time, with a number of different
> checks, it appeared that this *wasn't* the case. But while writing
> this very email, I had the bright idea that my time checkpoint was in
> slightly the wrong place; so sure enough, I found that I was timing
> out after only 72519 ns! (That is, 72 us, or well below the max write
> buffer time.)

So I can confirm that with the 1ms timeout, I actually am sometimes
timing out at 40 to 70 microseconds. I think this may have multiple
causes:
(1) uneven timer interrupts, as suggested by Huang?
(2) a jiffies timeout of 1 is two short (with HZ=1000, msecs_to_jiffies(1) is 1)

Regarding reason (2):

My thought (which matches with Imre's comments from his [1]) is that
one problem here is that we do not know how long it will be until the
*next* timer tick -- "waiting 1 jiffy" is really just waiting until
the next timer tick, which very well might be in 40us! So the correct
timeout calculation is something like:

uWriteTimeout = msecs_to_jiffies(1) + 1;

or with Imre's proposed methods (not merged upstream yet), just:

uWriteTimeout = msecs_to_jiffies_timeout(1);

Thoughts?

Note that a 2-jiffy timeout does not, in fact, totally resolve my
problems; with a timeout of 2 jiffies, I still get a timeout that
(according to getnstimeofday()) occurs after only 56us. It does
decrease its rate of occurrence, but Huang may still be right that
reason (1) is involved.

Brian

[1] http://marc.info/?l=linux-kernel&m=136854294730957


From imre.deak at intel.com  Wed Jun  5 18:39:06 2013
From: imre.deak at intel.com (Imre Deak)
Date: Thu, 06 Jun 2013 01:39:06 +0300
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer()
 timeout
In-Reply-To: <CAN8TOE8FRtQupXwvAtrVSN-C-nQz-XgOW7OA5C=XRs9YmCwTkg@mail.gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>
 <1370310406-413-3-git-send-email-computersforpeace@gmail.com>
 <51AD9140.90500@freescale.com>
 <CAN8TOE9UDGuQd9AbE-4UVcAiqCFpqhY=fX+LbrDybdgr16THdQ@mail.gmail.com>
 <CAN8TOE8FRtQupXwvAtrVSN-C-nQz-XgOW7OA5C=XRs9YmCwTkg@mail.gmail.com>
Message-ID: <1370471946.20138.67.camel@ideak-mobl>

On Wed, 2013-06-05 at 14:08 -0700, Brian Norris wrote:
> Adding a few others
> 
> For reference, this thread started with this patch:
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-June/047164.html
> 
> On Wed, Jun 5, 2013 at 11:01 AM, Brian Norris
> <computersforpeace at gmail.com> wrote:
> > On Tue, Jun 4, 2013 at 12:03 AM, Huang Shijie <b32955 at freescale.com> wrote:
> >> ? 2013?06?04? 09:46, Brian Norris ??:
> >>> After various tests, it seems simply that the timeout is not long enough
> >>> for my system; increasing it by a few jiffies prevented all failures
> >>> (testing for 12+ hours). There is no harm in increasing the timeout, but
> >>> there is harm in having it too short, as evidenced here.
> >>>
> >> I like the patch1 and patch 2.
> >>
> >> But extending the timeout from 1ms to 10ms is like a workaround. :)
> >
> > I was afraid you might say that; that's why I stuck the first two
> > patches first ;)
> ...
> >> I GUESS your problem is caused by the timer system, not the MTD code. I
> >> ever met this type of bug.
> ...
> >> I try to describe the jiffies bug with my poor english:
> >>
> >> [1] background:
> >> CONFIG_HZ=100, CONFIG_NO_HZ=y
> >>
> >> [2] call nand_wait() when we write a nand page.
> >>
> >> [3] The jiffies was not updated at a _even_ speed.
> >>
> >> In the nand_wait(), you wait for 20ms(2 jiffies) for a page write,
> >> and the timeout occurs during the page write. Of course, you think that
> >> we have already waited for 20ms.
> >> But in actually, we only waited for 1ms or less!
> >> How do i know this? I use the gettimeofday to check the real time when
> >> the timeout occur.
> >
> > I suspected this very type of thing, since this has come up in a few
> > different contexts. And for some time, with a number of different
> > checks, it appeared that this *wasn't* the case. But while writing
> > this very email, I had the bright idea that my time checkpoint was in
> > slightly the wrong place; so sure enough, I found that I was timing
> > out after only 72519 ns! (That is, 72 us, or well below the max write
> > buffer time.)
> 
> So I can confirm that with the 1ms timeout, I actually am sometimes
> timing out at 40 to 70 microseconds. I think this may have multiple
> causes:
> (1) uneven timer interrupts, as suggested by Huang?
> (2) a jiffies timeout of 1 is two short (with HZ=1000, msecs_to_jiffies(1) is 1)
> 
> Regarding reason (2):
> 
> My thought (which matches with Imre's comments from his [1]) is that
> one problem here is that we do not know how long it will be until the
> *next* timer tick -- "waiting 1 jiffy" is really just waiting until
> the next timer tick, which very well might be in 40us! So the correct
> timeout calculation is something like:
> 
> uWriteTimeout = msecs_to_jiffies(1) + 1;
> 
> or with Imre's proposed methods (not merged upstream yet), just:
> 
> uWriteTimeout = msecs_to_jiffies_timeout(1);
> 
> Thoughts?

I think what you describe at (2) wouldn't cause a premature timeout in
your case. The driver uses the returned jiffy value something like the
following in all cases (before applying the patch with the +1 change):

uWriteTimeout = msecs_to_jiffies(1);
timeout = jiffies + uWriteTimeout;
while (!condition)
	if (time_after(jiffies, timeout))
		return -ETIMEDOUT;

Here using time_after() as opposed to time_after_eq() serves as an
implicit +1 and thus guarantees that you wait at least 1 msec.

A bit off-topic:
Though using msecs_to_jiffies() is not a problem here, I think in this
case and almost always it would need less thinking and thus be safer to
still use msecs_to_jiffies_timeout(). A rare exception would be when the
+1 adjustment would accumulate to a significant error, like in the
following polling loop:

for (i = 0; i <= 50; i++) {
	if (poll_condition)
		return 0;
	schedule_timeout(msecs_to_jiffies(1));
}
return -ETIMEDOUT;

Here on HZ=1000 we would time out in average after 100 msec using
msecs_to_jiffies_timeout(1), whereas the intention was 50 msecs. 

--Imre

> Note that a 2-jiffy timeout does not, in fact, totally resolve my
> problems; with a timeout of 2 jiffies, I still get a timeout that
> (according to getnstimeofday()) occurs after only 56us. It does
> decrease its rate of occurrence, but Huang may still be right that
> reason (1) is involved.
> 
> Brian
> 
> [1] http://marc.info/?l=linux-kernel&m=136854294730957




From b32955 at freescale.com  Wed Jun  5 22:20:43 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Thu, 6 Jun 2013 10:20:43 +0800
Subject: [PATCH 3/3] mtd: cfi_cmdset_0002: increase do_write_buffer()
 timeout
In-Reply-To: <CAN8TOE8FRtQupXwvAtrVSN-C-nQz-XgOW7OA5C=XRs9YmCwTkg@mail.gmail.com>
References: <1370310406-413-1-git-send-email-computersforpeace@gmail.com>	<1370310406-413-3-git-send-email-computersforpeace@gmail.com>	<51AD9140.90500@freescale.com>	<CAN8TOE9UDGuQd9AbE-4UVcAiqCFpqhY=fX+LbrDybdgr16THdQ@mail.gmail.com>
 <CAN8TOE8FRtQupXwvAtrVSN-C-nQz-XgOW7OA5C=XRs9YmCwTkg@mail.gmail.com>
Message-ID: <51AFF1FB.1070100@freescale.com>

? 2013?06?06? 05:08, Brian Norris ??:
> Note that a 2-jiffy timeout does not, in fact, totally resolve my
> problems; with a timeout of 2 jiffies, I still get a timeout that
> (according to getnstimeofday()) occurs after only 56us. It does
since the 2-jiffy does not resolve your problem, i suggest you try the
latest linux-next
tree.


thanks
Huang Shijie



From pekon at ti.com  Thu Jun  6 08:40:23 2013
From: pekon at ti.com (Gupta, Pekon)
Date: Thu, 6 Jun 2013 12:40:23 +0000
Subject: UBI torture_peb() bad block detection problem
In-Reply-To: <CAN8TOE-HM07jwizD_4JA-4E9DnbUDk-Zm8mKz6TALJmKAkg9ww@mail.gmail.com>
References: <CAKGbVbtp4FBauCFNGSPTQSk_Dz4ELa7Gn31UByTMaFSk_vF1eg@mail.gmail.com>
 <1369812433.5446.226.camel@sauron.fi.intel.com>
 <CAN8TOE-HM07jwizD_4JA-4E9DnbUDk-Zm8mKz6TALJmKAkg9ww@mail.gmail.com>
Message-ID: <20980858CB6D3A4BAE95CA194937D5E73E9DABB9@DBDE04.ent.ti.com>

> Hi all,
> 
> On Wed, May 29, 2013 at 12:27 AM, Artem Bityutskiy
> <dedekind1 at gmail.com> wrote:
> > On Sat, 2013-04-27 at 21:57 +0800, Qiang Yu wrote:
> >> Hi guys,
> >>
> >> I'm writing MTD driver for Allwinner A10 nand controller. Now there is
> >> a problem with the UBI torture_peb() function. From the code and
> UBI
> >> doc, a PEB will be treated as bad when read with bit-flip after erase.
> >
> > The assumption that the MTD driver covers empty ereaseblocks with
> ECC,
> > so the erased areas are also protected. And the driver reports bit-flips
> > only if the amount of bits flipped is above the "safe" threshold, see
> > 'mtd_read()':
> >
> > return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
> >
> > So, your driver tells UBI: hey, this area has a dangeours amount of
> > bit-flips. And UBI knows that it just erased it, so the reaction is -
> > let me assume it is bad.
> 
> Note that there are kind of 3 classes of "bitflips" here:
> 1. A number of bitflips that are under the threshold. ECC corrects
> this "easily," and we report no error
> 2. A number of bitflips that is above the threshold, but still
> correctable by ECC (this returns EUCLEAN)
> 3. A number of bitflips that is above the correctability of the ECC
> algorithm (an "ECC error", returning EBADMSG)
> 
> However, we break this classification if (as is being discussed here)
> the ECC algorithm does not properly protect empty pages. For such ECC,
> I expect that all bitflips will actually be reported as uncorrectable
> (class 3, EBADMSG).
> 
> > So you should invent something in your driver to make it protect empty
> > NAND pages. Try to google, there were discussions about this.
> 
> I don't think this should always be done by the driver. As this is not
> the first driver to need such support, I think we should do something
> about it in nand_base.c. In fact, I was already considering submitting
> some work to handle this problem soon.
> 
> BTW, here is some prior discussion:
> 
> [1] http://lists.infradead.org/pipermail/linux-mtd/2012-July/042818.html
> [2] http://lists.infradead.org/pipermail/linux-mtd/2011-
> February/034139.html
> 
[Pekon]: I prefer [2] over [1], for following reasons
- program marker can itself be caused due to bit-flips in OOB area.
- As we are progressing towards BE-NAND (built-in ECC nands), having
  any metadata in OOB are should be avoided.
http://lists.infradead.org/pipermail/linux-mtd/2013-February/045885.html


> >> But with SAMSUNG K9GBG08U0A flash chip, sometimes the bit-flip
> does
> >> happen even after being erased.
> >
> > The assumption is that it should be corrected by ECC. -EUCLEAN should
> > not be reported if it is harmless. It should only be reported if there
> > are too many bit-flips.
> 
> I am guessing that where Qiang is speaking of bitflips, these actually
> turn up as EBADMSG (ECC error) and not as EUCLEAN, right? So the
> discussion should be about avoiding EBADMSG and instead returning
> EUCLEAN (or just 0, if we're under the threshold).
> 
> Now, assuming Qiang's problem is pretty similar to mine, a solution
> could work like the following:
> 
> 1. If nand_base receives an EBADMSG error code from a driver, do steps
> 2 through 5, for each ECC sector in the page
> 2. Count the number of 0 bits in the ECC sector (call it 'numzeros')
> 3. If numzeros > ecc_strength, return EBADMSG
> 4. Otherwise, clear the sector data to 0xff ("correcting" the sector)
> 5. Repeat 2-4 for each sector. If all sectors are "corrected", then
> return the max bitflips per sector
> 
> The above algorithm is not ideal for running often in SW, but
> fortunately, it would only be run for the uncommon case for a few
> reasons:
> [a] UBI shouldn't regularly need to read erased pages. This is
> primarily (only?) used for recovery from power-cuts.
> [b] Even when reading erased pages, we shouldn't see these flips "too
> often." I don't have hard numbers right now, but I don't believe we
> get these flips anywhere near 50% of the time when reading erased
> pages. Of course, this also varies depending on the (un)reliability of
> the flash medium.
> [c] For other EBADMSG (i.e., truly-corrupt data, not an erased page),
> we would quickly error out after seeing a few bytes of non-FFh data
> 
> All of this could be an opt-in feature for nand_base.c, where drivers
> can flag something like NAND_CHECK_FF_BITFLIPS (or some better-
> named
> flag).
> 
> Some form of this algorithm has already improved this very situation
> in my own out-of-tree driver, but I feel like it will be useful to
> include it in the generic code, rather than implementing ad-hoc
> solutions for every piece of hardware which uses an inflexible ECC
> scheme. (Of course, the best way is still to fix the ECC
> encoder/decoder to correct FFh pages, IMO.)
> 
> Thoughts?
> 

[Pekon]: IMHO add erase-page checks should be done:
(a) One time at block-level instead at each page-level accesses.
(b) On UBI write-path, instead of read path.
That is check for bit-flips in 'all' pages of a block before your are
picking erased PEB for writing.

Reasons below..
(1) you cannot erase single page, you have to erase complete
  Block (all pages need to be erased even if only one page has issue).
(2) suppose after writing a n-pages, you find (n+1)th erased page
  having lots of bit-flips beyond ECC strength, then what will you do
  with all the data written in earlier pages. Even if you schedule the
 PEB for scrubbing it wudn't help as PEB would have half-written 
 data, as (n+1)th page was not written correctly because of bit-flips.
 So, only option is pick another fresh erased PEB and re-write
 whole data from start (which is in-efficient).
(3) In most use-cases, NAND flash-reads would out-number
 flash-writes, thus we should keep flash-reads operations
 as simple as possible. Adding any extra checks to
chip->ecc.correct() or  chip-> ecc.calculate() would un-necessary
 load the read-path.
(4) bit-flips can be caused by read-disturbs, thus bit-flips can occur
 Later in time, much after page was erased. So better to check
 erase page just before writing. Therefore UBI also does a
 self-check before writing every new PEB.
(mtd/ubi/io.c: ubi_io_write -> self_check_not_bad)

So, IMHO its more efficient to add bit-flips checks somewhere in
mtd->_block_isbad(), so that this automatically gets in write-path
and is done for all pages in block.

comments ?


With regards, pekon


From renner at efe-gmbh.de  Thu Jun  6 10:47:06 2013
From: renner at efe-gmbh.de (Jens Renner (EFE))
Date: Thu, 06 Jun 2013 16:47:06 +0200
Subject: [RFC] Micron M25P80 Part name variants
In-Reply-To: <CAEgOgz6jjh9-G6PmzrjJcG7LKCnh4cAooSnCiZ9cmz_qUs8AXg@mail.gmail.com>
References: <CAEgOgz6jjh9-G6PmzrjJcG7LKCnh4cAooSnCiZ9cmz_qUs8AXg@mail.gmail.com>
Message-ID: <51B0A0EA.5000703@efe-gmbh.de>

Am 05.06.2013 07:57, schrieb Peter Crosthwaite:
> Hi All,
> 
> For micron M25P80 parts there is a mix of naming conventions in the
> device table:
> 
>         /* Micron */
>         { "n25q064",  INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
>         { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
>         { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
>         { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
> 
> n25q128 has a11 and a13 variants, while 256 does not. Should this be
> consistent across parts? If so should we adopt Liming Wangs "axx"
> precedent universally? Here is a hunk from Ed Maste that applies the
> relevant change to QEMU (currently on list) that would be nice to
> merge. Can we fix this Linux side in similar fashion?
> 
>      /* Micron */
> -    { INFO("n25q032a",    0x20bb16,      0,  64 << 10,  64, ER_4K) },
> -    { INFO("n25q128a11",  0x20bb18,      0,  64 << 10, 256, 0) },
> -    { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, 0) },
> -    { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512, ER_4K) },
> +    { INFO("n25q032a11",  0x20bb16,      0,  64 << 10,  64, ER_4K) },
> +    { INFO("n25q032a13",  0x20ba16,      0,  64 << 10,  64, ER_4K) },
> +    { INFO("n25q064a11",  0x20bb17,      0,  64 << 10, 128, ER_4K) },
> +    { INFO("n25q064a13",  0x20ba17,      0,  64 << 10, 128, ER_4K) },
> +    { INFO("n25q128a11",  0x20bb18,      0,  64 << 10, 256, ER_4K) },
> +    { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, ER_4K) },
> +    { INFO("n25q256a11",  0x20bb19,      0,  64 << 10, 512, ER_4K) },
> +    { INFO("n25q256a13",  0x20ba19,      0,  64 << 10, 512, ER_4K) },
> 
> Regards,
> Peter
> 

Hi Peter,

Thanks for your RFC, as I was thinking about the same thing. At the moment we
are testing various serial flash memories (Micron and others) on our own
Microblaze platform. In the N25Q256A datasheet and while testing I noticed that
there are specific features on the A83ESF40 and A83E1240 parts which the other
variants are lacking and vice versa. It is mainly about 4-byte access using
commands 12h (program), 13h (read), DCh (erase) that seem to be available only
on these two variants. Opposed to that the commands B7h, E9h (enter / exit
4-byte mode) are not supported by A83ESF40 and A83E1240.

If you want to use the upper 128 Mbit only one of the two methods actually
works. So relying on the manufacturer / device ID won't help because you still
don't know which is implemented by the component. In the code there is a check
if the device exceeds 64M, and if so it tries to activate 4-byte mode. (Btw,
the drawback of the dedicated 4-byte mode is that you run into problem when
using the flash also for Xilinx FPGA configuration which is 3-byte.) There was
a recent patch / proposal by Brian Norris to use 4-byte opcodes if available
just by checking the JEDEC ID:
http://lists.infradead.org/pipermail/linux-mtd/2013-April/046443.html
As he points out he was not able to distinguish between devices that support
the opcodes and those who don't.

So that might be something to consider when thinking about naming conventions.
Maybe I can contribute to this process; at least I could make some tests with
my Spartan-6 board and some flash devices.
Regards,

Jens.


From mpfj-list at newflow.co.uk  Thu Jun  6 15:18:09 2013
From: mpfj-list at newflow.co.uk (Mark Jackson)
Date: Thu, 06 Jun 2013 20:18:09 +0100
Subject: General question regarding multiple partitions on a single NOR device
Message-ID: <51B0E071.70909@newflow.co.uk>

On one of our products, we have 2 64Mbit NOR devices:- one to hold the
kernel, filesystem, etc, and the other to store "user" data.

The gotcha is that the "user" data is stored using our own wear
levelling code, with read / write / erase operations being carried out
on the raw flash device.

We are now designing a new CPU board with a single 1Gbit Spansion NOR
part on it, rather than the 2 separate devices.

I am planning to allocate 512Mbit to the "system" partitions (eg
bootloader, kernel, filesystem) and have the other 512Mbit as the "data"
partition.

Currently our wear levelling code uses mmap() to gain direct access to
the flash chip, which is not an issue, since all filesystem updates etc
are all carried out on the completely separate chip (via jffs2).

What I would like to know is, when the "system" and "user" partitions
reside on the *same" flash device, if I read/write directly to the
"user" partition, how do I maintain the jffs2 integrity on other
"system" partitions that may be doing their own read/write/erase
operations ?

If I can't read/write directly, can the same be achieved using the mtd
character device using something like:-

fd = open("/dev/mtd4", ..);
seek(fd, 1234);
write(fd, buff, ...);
...etc...

If I need to "manually" erase a sector on our custom data partition, how
can that be handled without disrupting any jffs2 flash access on the
other "system" partitions ?

Do the mtd ioctl() functions handle all the flash locking for me ?

Or is this a bit hole I'm digging for myself ?

Thanks for any help anyone can offer.

Regards
Mark J.


From weiyj.lk at gmail.com  Thu Jun  6 22:17:22 2013
From: weiyj.lk at gmail.com (Wei Yongjun)
Date: Fri, 7 Jun 2013 10:17:22 +0800
Subject: [PATCH] UBIFS: fix error return code in ubifs_remount_rw() and
 ubifs_fill_super()
Message-ID: <CAPgLHd_=Y=YwCWSFjcacJ14yKUidmmJTHnKKibU6haoBUeNacA@mail.gmail.com>

From: Wei Yongjun <yongjun_wei at trendmicro.com.cn>

Fix to return -ENOMEM in the kmalloc() and d_make_root() error handling
case instead of 0, as done elsewhere in those functions.

Signed-off-by: Wei Yongjun <yongjun_wei at trendmicro.com.cn>
---
 fs/ubifs/super.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index f21acf0..673b4bc 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1629,8 +1629,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
 	}
 
 	c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
-	if (!c->write_reserve_buf)
+	if (!c->write_reserve_buf) {
+		err = -ENOMEM;
 		goto out;
+	}
 
 	err = ubifs_lpt_init(c, 0, 1);
 	if (err)
@@ -2063,8 +2065,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 	}
 
 	sb->s_root = d_make_root(root);
-	if (!sb->s_root)
+	if (!sb->s_root) {
+		err = -ENOMEM;
 		goto out_umount;
+	}
 
 	mutex_unlock(&c->umount_mutex);
 	return 0;



From linux at prisktech.co.nz  Fri Jun  7 05:03:26 2013
From: linux at prisktech.co.nz (Tony Prisk)
Date: Fri, 07 Jun 2013 21:03:26 +1200
Subject: NAND buffer allocation fails
Message-ID: <51B1A1DE.3020603@prisktech.co.nz>

Could someone explain why the following situation might occur:

In drivers/mtd/nand/nand_base.c, we have:

int nand_scan_tail(struct mtd_info *mtd)
{
     int i;
     struct nand_chip *chip = mtd->priv;

     /* New bad blocks should be marked in OOB, flash-based BBT, or both */
     BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
             !(chip->bbt_options & NAND_BBT_USE_FLASH));

     if (!(chip->options & NAND_OWN_BUFFERS))
         chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
     if (!chip->buffers)
         return -ENOMEM;
...

For some reason, the kmalloc always fails on my configuration/hardware 
(arch-vt8500: WonderMedia/VIA APC8750).

The strange thing is that if I add the NAND_OWN_BUFFERS option, and 
allocate my own buffers in the driver probe everything is fine.
Driver probe code below:

     priv->nand.buffers = devm_kzalloc(priv->dev, 
sizeof(*priv->nand.buffers), GFP_KERNEL);
     if (!priv->nand.buffers) {
         dev_err(priv->dev, "failed to allocate NAND buffers\n");
         return -ENOMEM;
     }

The devm_kzalloc does occur earlier than the nand_scan_tail alloc would 
have, but there doesn't appear to be a shortage of memory on the 
platform so I don't think it's failing for a memory shortage.

Is there any real difference between using kmalloc and devm_kzalloc to 
allocate the buffer (other than the obvious 0'ing of the buffer)?
Why would one call fail and the other succeed?

Regards
Tony Prisk


From linux at prisktech.co.nz  Fri Jun  7 05:07:03 2013
From: linux at prisktech.co.nz (Tony Prisk)
Date: Fri, 07 Jun 2013 21:07:03 +1200
Subject: NAND buffer allocation fails
In-Reply-To: <51B1A1DE.3020603@prisktech.co.nz>
References: <51B1A1DE.3020603@prisktech.co.nz>
Message-ID: <51B1A2B7.6090602@prisktech.co.nz>


On 07/06/13 21:03, Tony Prisk wrote:
> Could someone explain why the following situation might occur:
>
> In drivers/mtd/nand/nand_base.c, we have:
>
> int nand_scan_tail(struct mtd_info *mtd)
> {
>     int i;
>     struct nand_chip *chip = mtd->priv;
>
>     /* New bad blocks should be marked in OOB, flash-based BBT, or 
> both */
>     BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
>             !(chip->bbt_options & NAND_BBT_USE_FLASH));
>
>     if (!(chip->options & NAND_OWN_BUFFERS))
>         chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
>     if (!chip->buffers)
>         return -ENOMEM;
> ...
>
> For some reason, the kmalloc always fails on my configuration/hardware 
> (arch-vt8500: WonderMedia/VIA APC8750).
>
> The strange thing is that if I add the NAND_OWN_BUFFERS option, and 
> allocate my own buffers in the driver probe everything is fine.
> Driver probe code below:
>
>     priv->nand.buffers = devm_kzalloc(priv->dev, 
> sizeof(*priv->nand.buffers), GFP_KERNEL);
>     if (!priv->nand.buffers) {
>         dev_err(priv->dev, "failed to allocate NAND buffers\n");
>         return -ENOMEM;
>     }
>
> The devm_kzalloc does occur earlier than the nand_scan_tail alloc 
> would have, but there doesn't appear to be a shortage of memory on the 
> platform so I don't think it's failing for a memory shortage.
>
> Is there any real difference between using kmalloc and devm_kzalloc to 
> allocate the buffer (other than the obvious 0'ing of the buffer)?
> Why would one call fail and the other succeed?
>
> Regards
> Tony Prisk

Resend to correct the linux-arm-kernel mailing list address.

Tony P


From elezegarcia at gmail.com  Fri Jun  7 10:22:48 2013
From: elezegarcia at gmail.com (Ezequiel Garcia)
Date: Fri, 7 Jun 2013 11:22:48 -0300
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <20130520123733.GB2904@localhost>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <20130520123733.GB2904@localhost>
Message-ID: <CALF0-+W+4NCLimsP1E+aGNLEuE9GtThsm6dNE-iyeju5ixx8Rg@mail.gmail.com>

On Mon, May 20, 2013 at 9:37 AM, Ezequiel Garcia
<ezequiel.garcia at free-electrons.com> wrote:
> Hi,
>
> (adding Eric Miao in Cc)
>
> On Tue, May 14, 2013 at 08:15:20AM -0300, Ezequiel Garcia wrote:
>> The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
>> is similar to the one in PXA SoC. Therefore, it should be possible to support
>> Armada NAND using pxa3xx-nand driver.
>>
>> While this effort is not ready yet, here is a set of patches that are needed
>> for such work.
>>
>> A small summary of the patches:
>>
>>   * 1/5 is a fix for a 2-year regression that removed DMA support.
>>
>>   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
>>
>>   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
>>     to successfully probe newer flash devices.
>>
>
> Since this patch affects directly the PXA hardware, I'd like to have some
> response from PXA maintainers.
>
> Guys, could you take a look at this?
>

Ping?

-- 
    Ezequiel


From haojian.zhuang at gmail.com  Sat Jun  8 03:22:04 2013
From: haojian.zhuang at gmail.com (Haojian Zhuang)
Date: Sat, 8 Jun 2013 15:22:04 +0800
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <CALF0-+W+4NCLimsP1E+aGNLEuE9GtThsm6dNE-iyeju5ixx8Rg@mail.gmail.com>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <20130520123733.GB2904@localhost>
 <CALF0-+W+4NCLimsP1E+aGNLEuE9GtThsm6dNE-iyeju5ixx8Rg@mail.gmail.com>
Message-ID: <CAN1soZxnG6oVpNT6dJ6WOAuLB5_JxTM6vrx-8j8qm-t1ZK8jFA@mail.gmail.com>

On Fri, Jun 7, 2013 at 10:22 PM, Ezequiel Garcia <elezegarcia at gmail.com> wrote:
> On Mon, May 20, 2013 at 9:37 AM, Ezequiel Garcia
> <ezequiel.garcia at free-electrons.com> wrote:
>> Hi,
>>
>> (adding Eric Miao in Cc)
>>
>> On Tue, May 14, 2013 at 08:15:20AM -0300, Ezequiel Garcia wrote:
>>> The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
>>> is similar to the one in PXA SoC. Therefore, it should be possible to support
>>> Armada NAND using pxa3xx-nand driver.
>>>
>>> While this effort is not ready yet, here is a set of patches that are needed
>>> for such work.
>>>
>>> A small summary of the patches:
>>>
>>>   * 1/5 is a fix for a 2-year regression that removed DMA support.
>>>
>>>   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
>>>
>>>   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
>>>     to successfully probe newer flash devices.
>>>
>>
>> Since this patch affects directly the PXA hardware, I'd like to have some
>> response from PXA maintainers.
>>
>> Guys, could you take a look at this?
>>
>
> Ping?
>
> --
>     Ezequiel

Hi Ezequiel,

As I didn't have the test environment, I looped some Marvell guys. But
they didn't
have any time on test it.

So let's loop Marek, Daniel & Igor. I hope that we could help us.

By the way, my zylonite pxa310 fails on running uboot. I can't fix it right now.

Regards
Haojian


From haojian.zhuang at gmail.com  Sat Jun  8 05:00:41 2013
From: haojian.zhuang at gmail.com (Haojian Zhuang)
Date: Sat, 8 Jun 2013 17:00:41 +0800
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <CAN1soZxnG6oVpNT6dJ6WOAuLB5_JxTM6vrx-8j8qm-t1ZK8jFA@mail.gmail.com>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <20130520123733.GB2904@localhost>
 <CALF0-+W+4NCLimsP1E+aGNLEuE9GtThsm6dNE-iyeju5ixx8Rg@mail.gmail.com>
 <CAN1soZxnG6oVpNT6dJ6WOAuLB5_JxTM6vrx-8j8qm-t1ZK8jFA@mail.gmail.com>
Message-ID: <CAN1soZwRqapXrT6REk_h3gy0Tus9pypUvrDYg=-eyv-FntOZUA@mail.gmail.com>

On Sat, Jun 8, 2013 at 3:22 PM, Haojian Zhuang <haojian.zhuang at gmail.com> wrote:
> On Fri, Jun 7, 2013 at 10:22 PM, Ezequiel Garcia <elezegarcia at gmail.com> wrote:
>> On Mon, May 20, 2013 at 9:37 AM, Ezequiel Garcia
>> <ezequiel.garcia at free-electrons.com> wrote:
>>> Hi,
>>>
>>> (adding Eric Miao in Cc)
>>>
>>> On Tue, May 14, 2013 at 08:15:20AM -0300, Ezequiel Garcia wrote:
>>>> The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
>>>> is similar to the one in PXA SoC. Therefore, it should be possible to support
>>>> Armada NAND using pxa3xx-nand driver.
>>>>
>>>> While this effort is not ready yet, here is a set of patches that are needed
>>>> for such work.
>>>>
>>>> A small summary of the patches:
>>>>
>>>>   * 1/5 is a fix for a 2-year regression that removed DMA support.
>>>>
>>>>   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
>>>>
>>>>   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
>>>>     to successfully probe newer flash devices.
>>>>
>>>
>>> Since this patch affects directly the PXA hardware, I'd like to have some
>>> response from PXA maintainers.
>>>
>>> Guys, could you take a look at this?
>>>
>>
>> Ping?
>>
>> --
>>     Ezequiel
>
> Hi Ezequiel,
>
> As I didn't have the test environment, I looped some Marvell guys. But
> they didn't
> have any time on test it.
>
> So let's loop Marek, Daniel & Igor. I hope that we could help us.
>
> By the way, my zylonite pxa310 fails on running uboot. I can't fix it right now.
>
> Regards
> Haojian

I'm OK on these patches.

Reviewed-by: Haojian Zhuang <haojian.zhuang at gmail.com>


From Julia.Lawall at lip6.fr  Sat Jun  8 11:36:23 2013
From: Julia.Lawall at lip6.fr (Julia Lawall)
Date: Sat,  8 Jun 2013 17:36:23 +0200
Subject: [PATCH] drivers/mtd/devices/bcm47xxsflash.c: correct argument to kfree
Message-ID: <1370705783-2140-1-git-send-email-Julia.Lawall@lip6.fr>

From: Julia Lawall <Julia.Lawall at lip6.fr>

The argument to kfree should not be the address of a structure field.
The argument is adjusted to correspond to what is found in the subsequent
remove function.

The semantic match that finds this problem is as follows:
(http://coccinelle.lip6.fr/)

// <smpl>
@@
expression e;
identifier f;
@@

* kfree(&e->f)
// </smpl>

Signed-off-by: Julia Lawall <Julia.Lawall at lip6.fr>

---
 drivers/mtd/devices/bcm47xxsflash.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
index 2060856..59848e7 100644
--- a/drivers/mtd/devices/bcm47xxsflash.c
+++ b/drivers/mtd/devices/bcm47xxsflash.c
@@ -155,7 +155,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 	return 0;
 
 err_dev_reg:
-	kfree(&b47s->mtd);
+	kfree(b47s);
 out:
 	return err;
 }



From zajec5 at gmail.com  Sat Jun  8 11:50:59 2013
From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=)
Date: Sat, 8 Jun 2013 17:50:59 +0200
Subject: [PATCH] drivers/mtd/devices/bcm47xxsflash.c: correct argument to
 kfree
In-Reply-To: <1370705783-2140-1-git-send-email-Julia.Lawall@lip6.fr>
References: <1370705783-2140-1-git-send-email-Julia.Lawall@lip6.fr>
Message-ID: <CACna6rwKDKriiw2Q+et02ZmhHU9U+7ni3ik=14XZDEnN54J3YQ@mail.gmail.com>

2013/6/8 Julia Lawall <Julia.Lawall at lip6.fr>:
> From: Julia Lawall <Julia.Lawall at lip6.fr>
>
> The argument to kfree should not be the address of a structure field.
> The argument is adjusted to correspond to what is found in the subsequent
> remove function.

This was already addressed in
[PATCH RESEND 1/2] mtd: bcm47: convert kzalloc to avoid invalid access

Artem: can you pick pointed patch, please? So people don't report it
over and over ;)

-- 
Rafa?


From ezequiel.garcia at free-electrons.com  Sat Jun  8 14:40:22 2013
From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia)
Date: Sat, 8 Jun 2013 15:40:22 -0300
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <CAN1soZwRqapXrT6REk_h3gy0Tus9pypUvrDYg=-eyv-FntOZUA@mail.gmail.com>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <20130520123733.GB2904@localhost>
 <CALF0-+W+4NCLimsP1E+aGNLEuE9GtThsm6dNE-iyeju5ixx8Rg@mail.gmail.com>
 <CAN1soZxnG6oVpNT6dJ6WOAuLB5_JxTM6vrx-8j8qm-t1ZK8jFA@mail.gmail.com>
 <CAN1soZwRqapXrT6REk_h3gy0Tus9pypUvrDYg=-eyv-FntOZUA@mail.gmail.com>
Message-ID: <20130608184021.GC2354@localhost>

On Sat, Jun 08, 2013 at 05:00:41PM +0800, Haojian Zhuang wrote:
> On Sat, Jun 8, 2013 at 3:22 PM, Haojian Zhuang <haojian.zhuang at gmail.com> wrote:
> > On Fri, Jun 7, 2013 at 10:22 PM, Ezequiel Garcia <elezegarcia at gmail.com> wrote:
> >> On Mon, May 20, 2013 at 9:37 AM, Ezequiel Garcia
> >> <ezequiel.garcia at free-electrons.com> wrote:
> >>> Hi,
> >>>
> >>> (adding Eric Miao in Cc)
> >>>
> >>> On Tue, May 14, 2013 at 08:15:20AM -0300, Ezequiel Garcia wrote:
> >>>> The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
> >>>> is similar to the one in PXA SoC. Therefore, it should be possible to support
> >>>> Armada NAND using pxa3xx-nand driver.
> >>>>
> >>>> While this effort is not ready yet, here is a set of patches that are needed
> >>>> for such work.
> >>>>
> >>>> A small summary of the patches:
> >>>>
> >>>>   * 1/5 is a fix for a 2-year regression that removed DMA support.
> >>>>
> >>>>   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
> >>>>
> >>>>   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
> >>>>     to successfully probe newer flash devices.
> >>>>
> >>>
> >>> Since this patch affects directly the PXA hardware, I'd like to have some
> >>> response from PXA maintainers.
> >>>
> >>> Guys, could you take a look at this?
> >>>
> >>
> >> Ping?
> >>
> >> --
> >>     Ezequiel
> >
> > Hi Ezequiel,
> >
> > As I didn't have the test environment, I looped some Marvell guys. But
> > they didn't
> > have any time on test it.
> >
> > So let's loop Marek, Daniel & Igor. I hope that we could help us.
> >

Great, thanks a lot! Let's hope they can give it a test...

> 
> I'm OK on these patches.
> 
> Reviewed-by: Haojian Zhuang <haojian.zhuang at gmail.com>

Great!

Thanks a lot,
-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com


From emilgoode at gmail.com  Sun Jun  9 05:08:22 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Sun,  9 Jun 2013 11:08:22 +0200
Subject: [PATCH] mtd: orion_nand: Improve error handling in orion_nand_probe
Message-ID: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>

This patch fixes some issues in the error handling and simplifies
the code by converting to devm* functions.

If the kzalloc call fails it is unnecessary to use the label no_res
and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
line 110 we forgett to call iounmap for the previous ioremap call.

The following changes are introduced:
- Convert to devm_kzalloc and remove calls to kfree.
- Convert to devm_ioremap_resource that adds a missing call to
  *request_mem_region and remove calls to iounmap.
- The devm_ioremap_resource function checks the passed resource so
  we can remove the NULL check after the platform_get_resource call.

Signed-off-by: Emil Goode <emilgoode at gmail.com>
---
The patch is only build tested

 drivers/mtd/nand/orion_nand.c |   39 +++++++++++----------------------------
 1 file changed, 11 insertions(+), 28 deletions(-)

diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 8fbd002..cc22f2f 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -85,34 +85,25 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 	int ret = 0;
 	u32 val = 0;
 
-	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
+	nc = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip) +
+			  sizeof(struct mtd_info), GFP_KERNEL);
 	if (!nc) {
 		printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
-		ret = -ENOMEM;
-		goto no_res;
+		return -ENOMEM;
 	}
 	mtd = (struct mtd_info *)(nc + 1);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto no_res;
-	}
-
-	io_base = ioremap(res->start, resource_size(res));
-	if (!io_base) {
-		printk(KERN_ERR "orion_nand: ioremap failed\n");
-		ret = -EIO;
-		goto no_res;
-	}
+	io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(io_base))
+		return PTR_ERR(io_base);
 
 	if (pdev->dev.of_node) {
 		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
-					GFP_KERNEL);
+				     GFP_KERNEL);
 		if (!board) {
 			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
-			ret = -ENOMEM;
-			goto no_res;
+			return -ENOMEM;
 		}
 		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
 			board->cle = (u8)val;
@@ -167,7 +158,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
 	if (nand_scan(mtd, 1)) {
 		ret = -ENXIO;
-		goto no_dev;
+		goto disable_clk;
 	}
 
 	mtd->name = "orion_nand";
@@ -176,20 +167,17 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 			board->parts, board->nr_parts);
 	if (ret) {
 		nand_release(mtd);
-		goto no_dev;
+		goto disable_clk;
 	}
 
 	return 0;
 
-no_dev:
+disable_clk:
 	if (!IS_ERR(clk)) {
 		clk_disable_unprepare(clk);
 		clk_put(clk);
 	}
 	platform_set_drvdata(pdev, NULL);
-	iounmap(io_base);
-no_res:
-	kfree(nc);
 
 	return ret;
 }
@@ -197,15 +185,10 @@ no_res:
 static int orion_nand_remove(struct platform_device *pdev)
 {
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
-	struct nand_chip *nc = mtd->priv;
 	struct clk *clk;
 
 	nand_release(mtd);
 
-	iounmap(nc->IO_ADDR_W);
-
-	kfree(nc);
-
 	clk = clk_get(&pdev->dev, NULL);
 	if (!IS_ERR(clk)) {
 		clk_disable_unprepare(clk);
-- 
1.7.10.4



From andy.shevchenko at gmail.com  Sun Jun  9 13:15:20 2013
From: andy.shevchenko at gmail.com (Andy Shevchenko)
Date: Sun, 9 Jun 2013 20:15:20 +0300
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
Message-ID: <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>

On Sun, Jun 9, 2013 at 12:08 PM, Emil Goode <emilgoode at gmail.com> wrote:
> This patch fixes some issues in the error handling and simplifies
> the code by converting to devm* functions.
>
> If the kzalloc call fails it is unnecessary to use the label no_res
> and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
> line 110 we forgett to call iounmap for the previous ioremap call.

"forget" (typo here)

> The following changes are introduced:
> - Convert to devm_kzalloc and remove calls to kfree.
> - Convert to devm_ioremap_resource that adds a missing call to
>   *request_mem_region and remove calls to iounmap.
> - The devm_ioremap_resource function checks the passed resource so
>   we can remove the NULL check after the platform_get_resource call.

What about another patch (that I guess should go first)  that converts
printk to dev_* or pr_*?

--
With Best Regards,
Andy Shevchenko


From dan.carpenter at oracle.com  Sun Jun  9 15:17:32 2013
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Sun, 9 Jun 2013 22:17:32 +0300
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
 <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
Message-ID: <20130609191732.GK28112@mwanda>

On Sun, Jun 09, 2013 at 08:15:20PM +0300, Andy Shevchenko wrote:
> On Sun, Jun 9, 2013 at 12:08 PM, Emil Goode <emilgoode at gmail.com> wrote:
> > This patch fixes some issues in the error handling and simplifies
> > the code by converting to devm* functions.
> >
> > If the kzalloc call fails it is unnecessary to use the label no_res
> > and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
> > line 110 we forgett to call iounmap for the previous ioremap call.
> 
> "forget" (typo here)
> 
> > The following changes are introduced:
> > - Convert to devm_kzalloc and remove calls to kfree.
> > - Convert to devm_ioremap_resource that adds a missing call to
> >   *request_mem_region and remove calls to iounmap.
> > - The devm_ioremap_resource function checks the passed resource so
> >   we can remove the NULL check after the platform_get_resource call.
> 
> What about another patch (that I guess should go first)  that converts
> printk to dev_* or pr_*?
> 

Huh, what?  Those are two totally unrelated things.  Emil's patch is
a bug fix.

Patches are applied in first come first serve order anyway, so I'm
not sure what you are saying.

regards,
dan carpenter



From andy.shevchenko at gmail.com  Sun Jun  9 15:27:03 2013
From: andy.shevchenko at gmail.com (Andy Shevchenko)
Date: Sun, 9 Jun 2013 22:27:03 +0300
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <20130609191732.GK28112@mwanda>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
 <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
 <20130609191732.GK28112@mwanda>
Message-ID: <CAHp75VcOMUVtfgXOQ+cyVpJN-XS7=yO1H8+8Nnw+LCgYWp7RPw@mail.gmail.com>

On Sun, Jun 9, 2013 at 10:17 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> On Sun, Jun 09, 2013 at 08:15:20PM +0300, Andy Shevchenko wrote:

[]

>> What about another patch (that I guess should go first)  that converts
>> printk to dev_* or pr_*?

> Huh, what?  Those are two totally unrelated things.  Emil's patch is
> a bug fix.

To be precise his patch is bugfix and cleanup at once.
My proposal is to add a clean up patch.

--
With Best Regards,
Andy Shevchenko


From dan.carpenter at oracle.com  Sun Jun  9 16:57:47 2013
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Sun, 9 Jun 2013 23:57:47 +0300
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <CAHp75VcOMUVtfgXOQ+cyVpJN-XS7=yO1H8+8Nnw+LCgYWp7RPw@mail.gmail.com>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
 <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
 <20130609191732.GK28112@mwanda>
 <CAHp75VcOMUVtfgXOQ+cyVpJN-XS7=yO1H8+8Nnw+LCgYWp7RPw@mail.gmail.com>
Message-ID: <20130609205747.GX23987@mwanda>

On Sun, Jun 09, 2013 at 10:27:03PM +0300, Andy Shevchenko wrote:
> On Sun, Jun 9, 2013 at 10:17 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> > On Sun, Jun 09, 2013 at 08:15:20PM +0300, Andy Shevchenko wrote:
> 
> []
> 
> >> What about another patch (that I guess should go first)  that converts
> >> printk to dev_* or pr_*?
> 
> > Huh, what?  Those are two totally unrelated things.  Emil's patch is
> > a bug fix.
> 
> To be precise his patch is bugfix and cleanup at once.
> My proposal is to add a clean up patch.

The printk idea isn't a bad one, it's just totally unrelated to what
the patch is doing.  You can't just randomly tell people to do a
bunch of work for no reason.  "Good bugfix, but before we apply it
you have to mow my lawn."

regards,
dan carpenter


From andy.shevchenko at gmail.com  Sun Jun  9 17:15:22 2013
From: andy.shevchenko at gmail.com (Andy Shevchenko)
Date: Mon, 10 Jun 2013 00:15:22 +0300
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <20130609205747.GX23987@mwanda>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
 <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
 <20130609191732.GK28112@mwanda>
 <CAHp75VcOMUVtfgXOQ+cyVpJN-XS7=yO1H8+8Nnw+LCgYWp7RPw@mail.gmail.com>
 <20130609205747.GX23987@mwanda>
Message-ID: <CAHp75VeDtfq3APDQsy2SP=wLrRPUJdVaBbfu4NcrWrC70wCebg@mail.gmail.com>

On Sun, Jun 9, 2013 at 11:57 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> On Sun, Jun 09, 2013 at 10:27:03PM +0300, Andy Shevchenko wrote:
>> On Sun, Jun 9, 2013 at 10:17 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
>> > On Sun, Jun 09, 2013 at 08:15:20PM +0300, Andy Shevchenko wrote:

>> >> What about another patch (that I guess should go first)  that converts
>> >> printk to dev_* or pr_*?
>>
>> > Huh, what?  Those are two totally unrelated things.  Emil's patch is
>> > a bug fix.
>>
>> To be precise his patch is bugfix and cleanup at once.
>> My proposal is to add a clean up patch.
>
> The printk idea isn't a bad one, it's just totally unrelated to what
> the patch is doing.

I don't agree with word 'totally'. It touches probe function and
shuffles code there.

>  You can't just randomly tell people to do a
> bunch of work for no reason.  "Good bugfix, but before we apply it
> you have to mow my lawn."

In this particular case I didn't think it's a big deal to fix 3 printfs.
Anyway, see patch in the next message.


--
With Best Regards,
Andy Shevchenko


From andy.shevchenko at gmail.com  Sun Jun  9 17:16:54 2013
From: andy.shevchenko at gmail.com (Andy Shevchenko)
Date: Mon, 10 Jun 2013 00:16:54 +0300
Subject: [PATCH] mtd: orion_nand: convert printk to dev_*
Message-ID: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>

It's better to use actual device name as a prefix in error messages.

Signed-off-by: Andy Shevchenko <andy.shevchenko at gmail.com>
---
 drivers/mtd/nand/orion_nand.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 8fbd002..ba38853 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -87,7 +87,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
 	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
 	if (!nc) {
-		printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
+		dev_err(&pdev->dev, "failed to allocate device structure.\n");
 		ret = -ENOMEM;
 		goto no_res;
 	}
@@ -101,7 +101,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
 	io_base = ioremap(res->start, resource_size(res));
 	if (!io_base) {
-		printk(KERN_ERR "orion_nand: ioremap failed\n");
+		dev_err(&pdev->dev, "ioremap failed\n");
 		ret = -EIO;
 		goto no_res;
 	}
@@ -110,7 +110,8 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
 					GFP_KERNEL);
 		if (!board) {
-			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
+			dev_err(&pdev->dev,
+				"failed to allocate board structure.\n");
 			ret = -ENOMEM;
 			goto no_res;
 		}
-- 
1.8.3.101.g727a46b



From dan.carpenter at oracle.com  Sun Jun  9 18:18:08 2013
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Mon, 10 Jun 2013 01:18:08 +0300
Subject: [PATCH] mtd: orion_nand: convert printk to dev_*
In-Reply-To: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>
References: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>
Message-ID: <20130609221808.GY23987@mwanda>

On Mon, Jun 10, 2013 at 12:16:54AM +0300, Andy Shevchenko wrote:
> It's better to use actual device name as a prefix in error messages.
> 

Gar...

This doesn't apply on top of Emil's patch.  Emil's patch was first
so it should go in first.  Also Emil's patch was a bugfix so it is
more important than this printk cleanup patch.

Really, the kzalloc error messages should just be deleted.  They are
cargo cult error messages as in "we need an error message because
we are copy and pasting from other code without thinking."  Kzalloc
already has far better messages built in.

Ah well...

regards,
dan carpenter


From andy.shevchenko at gmail.com  Sun Jun  9 18:31:27 2013
From: andy.shevchenko at gmail.com (Andy Shevchenko)
Date: Mon, 10 Jun 2013 01:31:27 +0300
Subject: [PATCH] mtd: orion_nand: convert printk to dev_*
In-Reply-To: <20130609221808.GY23987@mwanda>
References: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>
 <20130609221808.GY23987@mwanda>
Message-ID: <CAHp75VfYUL-odEZH4S3eskzD5Xs2Xc8Sbvy_7xE=yJaM1PiUBg@mail.gmail.com>

On Mon, Jun 10, 2013 at 1:18 AM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> On Mon, Jun 10, 2013 at 12:16:54AM +0300, Andy Shevchenko wrote:
>> It's better to use actual device name as a prefix in error messages.
>>
>
> Gar...
>
> This doesn't apply on top of Emil's patch.  Emil's patch was first
> so it should go in first.  Also Emil's patch was a bugfix so it is
> more important than this printk cleanup patch.

Which tree has that patch incorporated? I'm okay to rebase it against that tree.
Current version was done against recent linux-next.

--
With Best Regards,
Andy Shevchenko


From emilgoode at gmail.com  Sun Jun  9 18:39:20 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Mon, 10 Jun 2013 00:39:20 +0200
Subject: [PATCH] mtd: orion_nand: convert printk to dev_*
In-Reply-To: <20130609221808.GY23987@mwanda>
References: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>
 <20130609221808.GY23987@mwanda>
Message-ID: <20130609223920.GA3963@debian>

Hello Dan,

Thank you for pointing this out, I was going to send a second version
and fix that typo anyway so I will send a patch that applies on top
of Andy's patch and also remove that error message for kzalloc.

Best regards,

Emil

On Mon, Jun 10, 2013 at 01:18:08AM +0300, Dan Carpenter wrote:
> On Mon, Jun 10, 2013 at 12:16:54AM +0300, Andy Shevchenko wrote:
> > It's better to use actual device name as a prefix in error messages.
> > 
> 
> Gar...
> 
> This doesn't apply on top of Emil's patch.  Emil's patch was first
> so it should go in first.  Also Emil's patch was a bugfix so it is
> more important than this printk cleanup patch.
> 
> Really, the kzalloc error messages should just be deleted.  They are
> cargo cult error messages as in "we need an error message because
> we are copy and pasting from other code without thinking."  Kzalloc
> already has far better messages built in.
> 
> Ah well...
> 
> regards,
> dan carpenter


From emilgoode at gmail.com  Sun Jun  9 18:45:44 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Mon, 10 Jun 2013 00:45:44 +0200
Subject: [PATCH] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <CAHp75VeDtfq3APDQsy2SP=wLrRPUJdVaBbfu4NcrWrC70wCebg@mail.gmail.com>
References: <1370768902-20239-1-git-send-email-emilgoode@gmail.com>
 <CAHp75VftwuS4ZTFP5D90PhyzrAMoHVxDiSCg0jrMGp+r0eRfzA@mail.gmail.com>
 <20130609191732.GK28112@mwanda>
 <CAHp75VcOMUVtfgXOQ+cyVpJN-XS7=yO1H8+8Nnw+LCgYWp7RPw@mail.gmail.com>
 <20130609205747.GX23987@mwanda>
 <CAHp75VeDtfq3APDQsy2SP=wLrRPUJdVaBbfu4NcrWrC70wCebg@mail.gmail.com>
Message-ID: <20130609224544.GB3963@debian>

Hello,

Sorry for not responding earlier, I was away from my computer.
Thanks for the review, I will send a second version that applies
on top of Andy's patch and fix that typo in the change log.

Best regards,

Emil

On Mon, Jun 10, 2013 at 12:15:22AM +0300, Andy Shevchenko wrote:
> On Sun, Jun 9, 2013 at 11:57 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> > On Sun, Jun 09, 2013 at 10:27:03PM +0300, Andy Shevchenko wrote:
> >> On Sun, Jun 9, 2013 at 10:17 PM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> >> > On Sun, Jun 09, 2013 at 08:15:20PM +0300, Andy Shevchenko wrote:
> 
> >> >> What about another patch (that I guess should go first)  that converts
> >> >> printk to dev_* or pr_*?
> >>
> >> > Huh, what?  Those are two totally unrelated things.  Emil's patch is
> >> > a bug fix.
> >>
> >> To be precise his patch is bugfix and cleanup at once.
> >> My proposal is to add a clean up patch.
> >
> > The printk idea isn't a bad one, it's just totally unrelated to what
> > the patch is doing.
> 
> I don't agree with word 'totally'. It touches probe function and
> shuffles code there.
> 
> >  You can't just randomly tell people to do a
> > bunch of work for no reason.  "Good bugfix, but before we apply it
> > you have to mow my lawn."
> 
> In this particular case I didn't think it's a big deal to fix 3 printfs.
> Anyway, see patch in the next message.
> 
> 
> --
> With Best Regards,
> Andy Shevchenko


From emilgoode at gmail.com  Sun Jun  9 19:34:01 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Mon, 10 Jun 2013 01:34:01 +0200
Subject: [PATCH] mtd: orion_nand: convert printk to dev_*
In-Reply-To: <CAHp75VfYUL-odEZH4S3eskzD5Xs2Xc8Sbvy_7xE=yJaM1PiUBg@mail.gmail.com>
References: <1370812614-5724-1-git-send-email-andy.shevchenko@gmail.com>
 <20130609221808.GY23987@mwanda>
 <CAHp75VfYUL-odEZH4S3eskzD5Xs2Xc8Sbvy_7xE=yJaM1PiUBg@mail.gmail.com>
Message-ID: <20130609233401.GA4413@debian>

Hello Andy,

Thanks for the hint about converting to dev*. But I agree with Dan that error
messages for kzalloc calls are a bit pointless and after removing them all the
dev* calls are gone. So I will send a second version that fixes the typo and
removes the error messages for kzalloc. If you have any objections let me know. 

Best regards,

Emil

On Mon, Jun 10, 2013 at 01:31:27AM +0300, Andy Shevchenko wrote:
> On Mon, Jun 10, 2013 at 1:18 AM, Dan Carpenter <dan.carpenter at oracle.com> wrote:
> > On Mon, Jun 10, 2013 at 12:16:54AM +0300, Andy Shevchenko wrote:
> >> It's better to use actual device name as a prefix in error messages.
> >>
> >
> > Gar...
> >
> > This doesn't apply on top of Emil's patch.  Emil's patch was first
> > so it should go in first.  Also Emil's patch was a bugfix so it is
> > more important than this printk cleanup patch.
> 
> Which tree has that patch incorporated? I'm okay to rebase it against that tree.
> Current version was done against recent linux-next.
> 
> --
> With Best Regards,
> Andy Shevchenko


From emilgoode at gmail.com  Sun Jun  9 20:00:42 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Mon, 10 Jun 2013 02:00:42 +0200
Subject: [PATCH v2] mtd: orion_nand: Improve error handling in orion_nand_probe
Message-ID: <1370822442-25217-1-git-send-email-emilgoode@gmail.com>

This patch fixes some issues in the error handling and simplifies
the code by converting to devm* functions.

If the kzalloc call fails it is unnecessary to use the label no_res
and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
line 110 we forget to call iounmap for the previous ioremap call.

The following changes are introduced:
- Convert to devm_kzalloc and remove calls to kfree.
- Convert to devm_ioremap_resource that adds a missing call to
  *request_mem_region and remove calls to iounmap.
- The devm_ioremap_resource function checks the passed resource so
  we can remove the NULL check after the platform_get_resource call.

Signed-off-by: Emil Goode <emilgoode at gmail.com>
---
This patch is only build tested
v2: Fix change log typo and remove error messages for kzalloc calls

 drivers/mtd/nand/orion_nand.c |   49 +++++++++++++----------------------------
 1 file changed, 15 insertions(+), 34 deletions(-)

diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 8fbd002..76b9fba 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -85,35 +85,24 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 	int ret = 0;
 	u32 val = 0;
 
-	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
-	if (!nc) {
-		printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
-		ret = -ENOMEM;
-		goto no_res;
-	}
+	nc = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip) +
+			  sizeof(struct mtd_info), GFP_KERNEL);
+	if (!nc)
+		return -ENOMEM;
+
 	mtd = (struct mtd_info *)(nc + 1);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto no_res;
-	}
-
-	io_base = ioremap(res->start, resource_size(res));
-	if (!io_base) {
-		printk(KERN_ERR "orion_nand: ioremap failed\n");
-		ret = -EIO;
-		goto no_res;
-	}
+	io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(io_base))
+		return PTR_ERR(io_base);
 
 	if (pdev->dev.of_node) {
 		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
-					GFP_KERNEL);
-		if (!board) {
-			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
-			ret = -ENOMEM;
-			goto no_res;
-		}
+				     GFP_KERNEL);
+		if (!board)
+			return -ENOMEM;
+
 		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
 			board->cle = (u8)val;
 		else
@@ -167,7 +156,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
 	if (nand_scan(mtd, 1)) {
 		ret = -ENXIO;
-		goto no_dev;
+		goto disable_clk;
 	}
 
 	mtd->name = "orion_nand";
@@ -176,20 +165,17 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 			board->parts, board->nr_parts);
 	if (ret) {
 		nand_release(mtd);
-		goto no_dev;
+		goto disable_clk;
 	}
 
 	return 0;
 
-no_dev:
+disable_clk:
 	if (!IS_ERR(clk)) {
 		clk_disable_unprepare(clk);
 		clk_put(clk);
 	}
 	platform_set_drvdata(pdev, NULL);
-	iounmap(io_base);
-no_res:
-	kfree(nc);
 
 	return ret;
 }
@@ -197,15 +183,10 @@ no_res:
 static int orion_nand_remove(struct platform_device *pdev)
 {
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
-	struct nand_chip *nc = mtd->priv;
 	struct clk *clk;
 
 	nand_release(mtd);
 
-	iounmap(nc->IO_ADDR_W);
-
-	kfree(nc);
-
 	clk = clk_get(&pdev->dev, NULL);
 	if (!IS_ERR(clk)) {
 		clk_disable_unprepare(clk);
-- 
1.7.10.4



From jg1.han at samsung.com  Mon Jun 10 01:34:57 2013
From: jg1.han at samsung.com (Jingoo Han)
Date: Mon, 10 Jun 2013 14:34:57 +0900
Subject: [PATCH v2] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <1370822442-25217-1-git-send-email-emilgoode@gmail.com>
References: <1370822442-25217-1-git-send-email-emilgoode@gmail.com>
Message-ID: <001e01ce659c$3e582270$bb086750$@samsung.com>

Monday, June 10, 2013 9:01 AM, Emil Goode wrote:
> 
> This patch fixes some issues in the error handling and simplifies
> the code by converting to devm* functions.
> 
> If the kzalloc call fails it is unnecessary to use the label no_res
> and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
> line 110 we forget to call iounmap for the previous ioremap call.
> 
> The following changes are introduced:
> - Convert to devm_kzalloc and remove calls to kfree.
> - Convert to devm_ioremap_resource that adds a missing call to
>   *request_mem_region and remove calls to iounmap.
> - The devm_ioremap_resource function checks the passed resource so
>   we can remove the NULL check after the platform_get_resource call.
> 
> Signed-off-by: Emil Goode <emilgoode at gmail.com>
> ---
> This patch is only build tested
> v2: Fix change log typo and remove error messages for kzalloc calls
> 
>  drivers/mtd/nand/orion_nand.c |   49 +++++++++++++----------------------------
>  1 file changed, 15 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
> index 8fbd002..76b9fba 100644
> --- a/drivers/mtd/nand/orion_nand.c
> +++ b/drivers/mtd/nand/orion_nand.c
> @@ -85,35 +85,24 @@ static int __init orion_nand_probe(struct platform_device *pdev)
>  	int ret = 0;
>  	u32 val = 0;
> 
> -	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
> -	if (!nc) {
> -		printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");

CC'ed Dan Carpenter, Andy Shevchenko

You don't need to remove this error message.
You would replace 'printk(KERN_ERR "orion_nand:...)' with
'dev_err(&pdev->dev,)'.

	dev_err("failed to allocate device structure.\n");


> -		ret = -ENOMEM;
> -		goto no_res;
> -	}
> +	nc = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip) +
> +			  sizeof(struct mtd_info), GFP_KERNEL);
> +	if (!nc)
> +		return -ENOMEM;
> +
>  	mtd = (struct mtd_info *)(nc + 1);
> 
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!res) {
> -		ret = -ENODEV;
> -		goto no_res;
> -	}
> -
> -	io_base = ioremap(res->start, resource_size(res));
> -	if (!io_base) {
> -		printk(KERN_ERR "orion_nand: ioremap failed\n");

Yes, this error message is not necessary.
devm_ioremap_resource() provides its own error messages; so all
explicit error messages can be removed from the failure code paths.


> -		ret = -EIO;
> -		goto no_res;
> -	}
> +	io_base = devm_ioremap_resource(&pdev->dev, res);

How about using devm_ioremap() instead of devm_ioremap_resource()?

Only ioremap() was used previously; however, devm_ioremap_resource()
internally calls both devm_request_mem_region() and devm_ioremap().

If it is wrong, please let me know kindly. :)


> +	if (IS_ERR(io_base))
> +		return PTR_ERR(io_base);
> 
>  	if (pdev->dev.of_node) {
>  		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
> -					GFP_KERNEL);
> -		if (!board) {
> -			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");

As above mentioned, you don't need to remove this error message.
You would replace 'printk(KERN_ERR "orion_nand:...)' with
'dev_err(&pdev->dev,)'.

	dev_err("failed to allocate board structure.\n");


Best regards,
Jingoo Han


> -			ret = -ENOMEM;
> -			goto no_res;
> -		}
> +				     GFP_KERNEL);
> +		if (!board)
> +			return -ENOMEM;
> +
>  		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
>  			board->cle = (u8)val;
>  		else
> @@ -167,7 +156,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> 
>  	if (nand_scan(mtd, 1)) {
>  		ret = -ENXIO;
> -		goto no_dev;
> +		goto disable_clk;
>  	}
> 
>  	mtd->name = "orion_nand";
> @@ -176,20 +165,17 @@ static int __init orion_nand_probe(struct platform_device *pdev)
>  			board->parts, board->nr_parts);
>  	if (ret) {
>  		nand_release(mtd);
> -		goto no_dev;
> +		goto disable_clk;
>  	}
> 
>  	return 0;
> 
> -no_dev:
> +disable_clk:
>  	if (!IS_ERR(clk)) {
>  		clk_disable_unprepare(clk);
>  		clk_put(clk);
>  	}
>  	platform_set_drvdata(pdev, NULL);
> -	iounmap(io_base);
> -no_res:
> -	kfree(nc);
> 
>  	return ret;
>  }
> @@ -197,15 +183,10 @@ no_res:
>  static int orion_nand_remove(struct platform_device *pdev)
>  {
>  	struct mtd_info *mtd = platform_get_drvdata(pdev);
> -	struct nand_chip *nc = mtd->priv;
>  	struct clk *clk;
> 
>  	nand_release(mtd);
> 
> -	iounmap(nc->IO_ADDR_W);
> -
> -	kfree(nc);
> -
>  	clk = clk_get(&pdev->dev, NULL);
>  	if (!IS_ERR(clk)) {
>  		clk_disable_unprepare(clk);
> --
> 1.7.10.4



From josh.wu at atmel.com  Mon Jun 10 06:26:48 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:48 +0800
Subject: [PATCH v3 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC)
 support
Message-ID: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>

This patch series enable NFC support for SAMA5 soc. It can send command,
address cycles automaticly. Also when enable NFC sram, NFC will transfer
data to sram. Which can save lots of cpu time.

The mtd speed test results (non-NFC vs NFC), run in sama5d3x-ek with DMA
enable, is in the end of this patch.

v2 --> v3:
 1) Change the dts usage for NFC. Now use a NFC child node of atmel nand
    to enable NFC driver. In this way the atmel nand driver will include
    a NFC driver, which will be probed if dts has NFC node.
 2) can enable/disable NFC write by sram in dts.
 3) merged J.C's patch(use devm_xxx to simple the code) in this series.
 4) remove unused NFC register definitions. Change the definition names.
 5) trival fix accroding to J.C's suggestion.
 6) modify the ofpart.c for child node check. If the child node has compatible
    property then this node is a device not a partition.

v1 --> v2:
 1) rebase it with latest l2-mtd git tree: 
    - remove useless nand commands (NAND_CMD_DEPLETE1, NAND_CMD_STATUS_ERRORx).
    - adopt to the new nand write function's parameters. Add error message when
      handle subpage write via nfc sram.
 2) rewrite pmecc_enable function. Now I use exist NAND_ECC_READ/WRITE const
    instead of using a new enum definition.

Jean-Christophe PLAGNIOL-VILLARD (1):
  MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap

Josh Wu (5):
  mtd: atmel_nand: replace pmecc enable code with one function.
  mtd: atmel_nand: add Nand Flash Controller (NFC) support
  mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via
    sram
  mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
  mtd: ofpart: add compatible check for child nodes

 .../devicetree/bindings/mtd/atmel-nand.txt         |   28 +
 drivers/mtd/nand/atmel_nand.c                      |  840 ++++++++++++++++----
 drivers/mtd/nand/atmel_nand_nfc.h                  |   94 +++
 drivers/mtd/ofpart.c                               |   14 +-
 4 files changed, 832 insertions(+), 144 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h

mtd_speedtest is run in 60M partition with DMA enabled for two cases:
 1. Using NFC and sram read/write with DMA enabled.
 2. Using Non-NFC with DMA enabled.

Summary of the two test results:
 1. With NFC and sram read/write enabled, the write speed will become %10 slower
    and the cpu load also is reduce a lot (50% -> 20%):
                          Non-NFC                  NFC
      Page write Speed:   5536KiB : 46% ~ 64% --> 4989KiB : 13% ~ 22%
      2 Page write speed: 5567KiB : 52% ~ 69% --> 5043KiB : 10% ~ 20%

 2. With NFC and sram read/write enabled, the read speed is almost same and the
    cpu load is reduced (30% -> 15%):
                          Non-NFC                  NFC
      Page read Speed:    9361KiB : %24 ~ 46% --> 9340KiB : 13% ~ 19%
      2 Page read Speed:  9361KiB : %21 ~ 57% --> 9426KiB :  8% ~ 15%

Following is the detail test log:

case 1: Non-NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
top -n 130 -d 1 | grep speedtest
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     D     1164   0%  53% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  58% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  53% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  60% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock write speed is 5594 KiB/s
mtd_speedtest: testing eraseblock read speed
  513   504 root     R     1164   0%  27% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   5% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   1% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   2% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   1% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock read speed is 9442 KiB/s
mtd_speedtest: testing page write speed
  513   504 root     R     1164   0%  46% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  64% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  64% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  60% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page write speed is 5536 KiB/s
mtd_speedtest: testing page read speed
  513   504 root     R     1164   0%  46% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  30% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  30% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  26% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  25% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page read speed is 9361 KiB/s
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: testing 2 page write speed
  513   504 root     R     1164   0%  69% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  61% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  61% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  52% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  58% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page write speed is 5567 KiB/s
mtd_speedtest: testing 2 page read speed
  513   504 root     D     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  26% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  21% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  23% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  25% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  23% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9361 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 167411 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
  513   504 root     R     1164   0%  74% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 4x multi-block erase speed is 301176 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 325079 KiB/s
mtd_speedtest: finished
=================================================


case 2: NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
top -n 130 -d 1 | grep speedtest
mtd_speedtest: testing eraseblock write speed
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  10% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     D     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     D     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   9% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock write speed is 5105 KiB/s
mtd_speedtest: testing eraseblock read speed
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   6% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock read speed is 9512 KiB/s
  514   504 root     R     1164   0%   6% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: testing page write speed
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  22% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page write speed is 4989 KiB/s
mtd_speedtest: testing page read speed
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  18% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  19% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page read speed is 9340 KiB/s
mtd_speedtest: testing 2 page write speed
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  10% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  18% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page write speed is 5043 KiB/s
mtd_speedtest: testing 2 page read speed
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   9% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9426 KiB/s
mtd_speedtest: Testing erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: erase speed is 157943 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 308743 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 315076 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 32x multi-block erase speed is 298252 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 311878 KiB/s
mtd_speedtest: finished
=================================================

-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:49 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:49 +0800
Subject: [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc,
 gpio and ioremap
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-2-git-send-email-josh.wu@atmel.com>

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre at atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
 drivers/mtd/nand/atmel_nand.c |  148 ++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..c7a4016 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -366,43 +366,34 @@ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 			table_size * sizeof(int16_t);
 }
 
-static void pmecc_data_free(struct atmel_nand_host *host)
-{
-	kfree(host->pmecc_partial_syn);
-	kfree(host->pmecc_si);
-	kfree(host->pmecc_lmu);
-	kfree(host->pmecc_smu);
-	kfree(host->pmecc_mu);
-	kfree(host->pmecc_dmu);
-	kfree(host->pmecc_delta);
-}
-
 static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
 	const int cap = host->pmecc_corr_cap;
+	int size;
+
+	size = (2 * cap + 1) * sizeof(int16_t);
+	host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_lmu = devm_kzalloc(host->dev,
+			(cap + 1) * sizeof(int16_t), GFP_KERNEL);
+	host->pmecc_smu = devm_kzalloc(host->dev,
+			(cap + 2) * size, GFP_KERNEL);
+
+	size = (cap + 1) * sizeof(int);
+	host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
+
+	if (!host->pmecc_partial_syn ||
+		!host->pmecc_si ||
+		!host->pmecc_lmu ||
+		!host->pmecc_smu ||
+		!host->pmecc_mu ||
+		!host->pmecc_dmu ||
+		!host->pmecc_delta)
+		return -ENOMEM;
 
-	host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-
-	if (host->pmecc_partial_syn &&
-			host->pmecc_si &&
-			host->pmecc_lmu &&
-			host->pmecc_smu &&
-			host->pmecc_mu &&
-			host->pmecc_dmu &&
-			host->pmecc_delta)
-		return 0;
-
-	/* error happened */
-	pmecc_data_free(host);
-	return -ENOMEM;
+	return 0;
 }
 
 static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
@@ -1023,27 +1014,27 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
+	host->ecc = devm_request_and_ioremap(&pdev->dev, regs);
 	if (host->ecc == NULL) {
 		dev_err(host->dev, "ioremap failed\n");
 		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		goto err;
 	}
 
 	regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
 	if (regs_pmerr && regs_rom) {
-		host->pmerrloc_base = ioremap(regs_pmerr->start,
-			resource_size(regs_pmerr));
-		host->pmecc_rom_base = ioremap(regs_rom->start,
-			resource_size(regs_rom));
+		host->pmerrloc_base = devm_request_and_ioremap(&pdev->dev,
+				regs_pmerr);
+		host->pmecc_rom_base = devm_request_and_ioremap(&pdev->dev,
+				regs_rom);
 	}
 
 	if (!host->pmerrloc_base || !host->pmecc_rom_base) {
 		dev_err(host->dev,
 			"Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
 		err_no = -EIO;
-		goto err_pmloc_ioremap;
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1068,7 +1059,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
 			dev_err(host->dev, "No room for ECC bytes\n");
 			err_no = -EINVAL;
-			goto err_no_ecc_room;
+			goto err;
 		}
 		pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
 					mtd->oobsize,
@@ -1093,7 +1084,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 	if (err_no) {
 		dev_err(host->dev,
 				"Cannot allocate memory for PMECC computation!\n");
-		goto err_pmecc_data_alloc;
+		goto err;
 	}
 
 	nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
@@ -1103,15 +1094,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 
 	return 0;
 
-err_pmecc_data_alloc:
-err_no_ecc_room:
-err_pmloc_ioremap:
-	iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-err_pmecc_ioremap:
+err:
 	return err_no;
 }
 
@@ -1414,7 +1397,7 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
+	host->ecc = devm_request_and_ioremap(&pdev->dev, regs);
 	if (host->ecc == NULL) {
 		dev_err(host->dev, "ioremap failed\n");
 		return -EIO;
@@ -1479,20 +1462,19 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	}
 
 	/* Allocate memory for the device structure (and zero it) */
-	host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 	if (!host) {
 		printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
 		return -ENOMEM;
 	}
 
-	host->io_phys = (dma_addr_t)mem->start;
-
-	host->io_base = ioremap(mem->start, resource_size(mem));
+	host->io_base = devm_request_and_ioremap(&pdev->dev, mem);
 	if (host->io_base == NULL) {
 		printk(KERN_ERR "atmel_nand: ioremap failed\n");
 		res = -EIO;
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1500,7 +1482,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	if (pdev->dev.of_node) {
 		res = atmel_of_init_port(host, pdev->dev.of_node);
 		if (res)
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 	} else {
 		memcpy(&host->board, pdev->dev.platform_data,
 		       sizeof(struct atmel_nand_data));
@@ -1519,16 +1501,17 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	if (IS_ERR(pinctrl)) {
 		dev_err(host->dev, "Failed to request pinctrl\n");
 		res = PTR_ERR(pinctrl);
-		goto err_ecc_ioremap;
+		goto err_nand_ioremap;
 	}
 
 	if (gpio_is_valid(host->board.rdy_pin)) {
-		res = gpio_request(host->board.rdy_pin, "nand_rdy");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.rdy_pin, "nand_rdy");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request rdy gpio %d\n",
 				host->board.rdy_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		res = gpio_direction_input(host->board.rdy_pin);
@@ -1536,19 +1519,20 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"can't request input direction rdy gpio %d\n",
 				host->board.rdy_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		nand_chip->dev_ready = atmel_nand_device_ready;
 	}
 
 	if (gpio_is_valid(host->board.enable_pin)) {
-		res = gpio_request(host->board.enable_pin, "nand_enable");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.enable_pin, "nand_enable");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request enable gpio %d\n",
 				host->board.enable_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		res = gpio_direction_output(host->board.enable_pin, 1);
@@ -1556,7 +1540,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"can't request output direction enable gpio %d\n",
 				host->board.enable_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 	}
 
@@ -1573,7 +1557,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	atmel_nand_enable(host);
 
 	if (gpio_is_valid(host->board.det_pin)) {
-		res = gpio_request(host->board.det_pin, "nand_det");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.det_pin, "nand_det");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request det gpio %d\n",
@@ -1651,16 +1636,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return res;
 
 err_scan_tail:
-	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-		pmecc_data_free(host);
-	}
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
 err_hw_ecc:
 err_scan_ident:
 err_no_card:
@@ -1668,10 +1645,7 @@ err_no_card:
 	platform_set_drvdata(pdev, NULL);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1691,31 +1665,11 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
 		pmerrloc_writel(host->pmerrloc_base, ELDIS,
 				PMERRLOC_DISABLE);
-		pmecc_data_free(host);
 	}
 
-	if (gpio_is_valid(host->board.det_pin))
-		gpio_free(host->board.det_pin);
-
-	if (gpio_is_valid(host->board.enable_pin))
-		gpio_free(host->board.enable_pin);
-
-	if (gpio_is_valid(host->board.rdy_pin))
-		gpio_free(host->board.rdy_pin);
-
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
-	iounmap(host->io_base);
-	kfree(host);
-
 	return 0;
 }
 
-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:50 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:50 +0800
Subject: [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one
 function.
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-3-git-send-email-josh.wu@atmel.com>

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
 drivers/mtd/nand/atmel_nand.c |   40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index c7a4016..7236415 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -754,6 +754,29 @@ normal_check:
 	return total_err;
 }
 
+static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
+{
+	u32 val;
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+	val = pmecc_readl_relaxed(host->ecc, CFG);
+
+	if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
+		dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
+		return;
+	}
+
+	if (ecc_op == NAND_ECC_READ)
+		pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
+			| PMECC_CFG_AUTO_ENABLE);
+	else
+		pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
+			& ~PMECC_CFG_AUTO_ENABLE);
+
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+}
+
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 {
@@ -765,13 +788,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	unsigned long end_time;
 	int bitflips = 0;
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
-		& ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+	pmecc_enable(host, NAND_ECC_READ);
 
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
@@ -804,14 +821,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 	int i, j;
 	unsigned long end_time;
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
-		PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+	pmecc_enable(host, NAND_ECC_WRITE);
 
 	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
 
-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:51 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:51 +0800
Subject: =?UTF-8?q?=5BPATCH=203/6=5D=20mtd=3A=20atmel=5Fnand=3A=20add=20Nand=20Flash=20Controller=20=28NFC=29=20support?=
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-4-git-send-email-josh.wu@atmel.com>

Nand Flash Controller (NFC) can handle automatic transfers, sending the
commands and address cycles to the NAND Flash.

To use NFC in this driver, user needs to add NFC child node in nand flash
driver. The NFC child node includes NFC's compatible string and regiters
of the address and size of NFC command registers, NFC registers (embedded
in HSMC) and NFC SRAM.
Also user need to set up the HSMC irq, which use to check whether nfc
command is finish or not.

This driver has been tested on SAMA5D3X-EK board with JFFS2, YAFFS,
UBIFS and mtd-utils.

I put the part of the mtd_speedtest result here for your information.
>From the mtd_speedtest, we can see the NFC will reduce the %50 of cpu load
when writing nand flash. No change when reading.
In the meantime, the speed will be slow about %8.

- commands use to test:
    #insmod /mnt/mtd_speedtest.ko dev=2 &
    #top -n 30 -d 1 | grep speedtest

- test result:

Before the patch:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
  515   495 root     R     1164   0%  93% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  99% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5768 KiB/s
mtd_speedtest: testing eraseblock read speed
  515   495 root     R     1164   0%  92% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 5932 KiB/s
mtd_speedtest: testing page write speed
  515   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5770 KiB/s
mtd_speedtest: testing page read speed
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  89% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5910 KiB/s

After the patch:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock write speed
  509   495 root     D     1164   0%  49% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  50% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  47% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5370 KiB/s
mtd_speedtest: testing eraseblock read speed
  509   495 root     R     1164   0%  92% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  95% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 5715 KiB/s
mtd_speedtest: testing page write speed
  509   495 root     D     1164   0%  48% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  47% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  50% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5224 KiB/s
mtd_speedtest: testing page read speed
  509   495 root     R     1164   0%  89% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  93% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5641 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v2 --> v3:
  - Add a NFC child node of atmel nand to enable NFC.
  - So add a NFC driver which use to initialize the NFC reg resources.
  - remove unused NFC register definitions.
  - modify NFC register definition names.

 .../devicetree/bindings/mtd/atmel-nand.txt         |   26 ++
 drivers/mtd/nand/atmel_nand.c                      |  410 ++++++++++++++++++--
 drivers/mtd/nand/atmel_nand_nfc.h                  |   94 +++++
 3 files changed, 497 insertions(+), 33 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index d555421..6a267cb 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -29,6 +29,12 @@ Optional properties:
   sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
+  - Required properties:
+    - compatible : "atmel,sama5d3-nfc".
+    - reg : should specify the address and size used for NFC command registers,
+            NFC registers and NFC Sram. NFC Sram address and size can be absent
+            if don't want to use it.
 
 Examples:
 nand0: nand at 40000000,0 {
@@ -77,3 +83,23 @@ nand0: nand at 40000000 {
 		...
 	};
 };
+
+/* for NFC supported chips */
+nand0: nand at 40000000 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+        ...
+        nfc at 70000000 {
+		compatible = "atmel,sama5d3-nfc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <
+			0x70000000 0x10000000	/* NFC Command Registers */
+			0xffffc000 0x00000070	/* NFC HSMC regs */
+			0x00200000 0x00100000	/* NFC SRAM banks */
+		>;
+	};
+};
+
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7236415..bf3370b 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     ? Copyright 2012 ATMEL, Hong Xu
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     ? Copyright 2013 ATMEL, Josh Wu (josh.wu at atmel.com)
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -37,9 +40,11 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/platform_data/atmel.h>
 #include <linux/pinctrl/consumer.h>
 
@@ -58,6 +63,7 @@ module_param(on_flash_bbt, int, 0);
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
+#include "atmel_nand_nfc.h"	/* Nand Flash Controller definition */
 
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -85,6 +91,17 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 	},
 };
 
+struct atmel_nfc {
+	void __iomem		*base_cmd_regs;
+	void __iomem		*hsmc_regs;
+	void __iomem		*sram_bank0;
+	dma_addr_t		sram_bank0_phys;
+
+	bool			is_initialized;
+	struct completion	comp_nfc;
+};
+static struct atmel_nfc	nand_nfc;
+
 struct atmel_nand_host {
 	struct nand_chip	nand_chip;
 	struct mtd_info		mtd;
@@ -97,6 +114,8 @@ struct atmel_nand_host {
 	struct completion	comp;
 	struct dma_chan		*dma_chan;
 
+	struct atmel_nfc	*nfc;
+
 	bool			has_pmecc;
 	u8			pmecc_corr_cap;
 	u16			pmecc_sector_size;
@@ -186,6 +205,55 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
 }
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	if (gpio_is_valid(host->board.rdy_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.rdy_pin, "nand_rdy");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		res = gpio_direction_input(host->board.rdy_pin);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request input direction rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		chip->dev_ready = atmel_nand_device_ready;
+	}
+
+	if (gpio_is_valid(host->board.enable_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.enable_pin, "nand_enable");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+
+		res = gpio_direction_output(host->board.enable_pin, 1);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request output direction enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+	}
+	return res;
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -1341,6 +1409,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
 	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 
+	/* load the nfc driver if there is */
+	of_platform_populate(np, NULL, NULL, host->dev);
+
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 		return 0;	/* Not using PMECC */
 
@@ -1452,6 +1523,238 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 	return 0;
 }
 
+/* SMC interrupt service routine */
+static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
+{
+	struct atmel_nand_host *host = dev_id;
+	u32 status, mask, pending;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	status = nfc_readl(host->nfc->hsmc_regs, SR);
+	mask = nfc_readl(host->nfc->hsmc_regs, IMR);
+	pending = status & mask;
+
+	if (pending & NFC_SR_XFR_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
+	} else if (pending & NFC_SR_RB_EDGE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
+	} else if (pending & NFC_SR_CMD_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
+	} else {
+		ret = IRQ_NONE;
+	}
+
+	return ret;
+}
+
+/* NFC(Nand Flash Controller) related functions */
+static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
+{
+	unsigned long timeout;
+	init_completion(&host->nfc->comp_nfc);
+
+	/* Enable interrupt that need to wait for */
+	nfc_writel(host->nfc->hsmc_regs, IER, flag);
+
+	timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
+			msecs_to_jiffies(NFC_TIME_OUT_MS));
+	if (timeout)
+		return 0;
+
+	/* Time out to wait for the interrupt */
+	dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
+	return -ETIMEDOUT;
+}
+
+static int nfc_send_command(struct atmel_nand_host *host,
+	unsigned int cmd, unsigned int addr, unsigned char cycle0)
+{
+	unsigned long timeout;
+	dev_dbg(host->dev,
+		"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
+		cmd, addr, cycle0);
+
+	timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+	while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
+			& NFCADDR_CMD_NFCBUSY) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(host->dev,
+				"Time out to wait CMD_NFCBUSY ready!\n");
+			return -ETIMEDOUT;
+		}
+	}
+	nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
+	nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
+	return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
+}
+
+static int nfc_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+	if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
+		return 1;
+	return 0;
+}
+
+static void nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+
+	if (chip == -1)
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
+	else
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
+}
+
+static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
+		unsigned int *addr1234, unsigned int *cycle0)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	int acycle = 0;
+	unsigned char addr_bytes[8];
+	int index = 0, bit_shift;
+
+	BUG_ON(addr1234 == NULL || cycle0 == NULL);
+
+	*cycle0 = 0;
+	*addr1234 = 0;
+
+	if (column != -1) {
+		if (chip->options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		addr_bytes[acycle++] = column & 0xff;
+		if (mtd->writesize > 512)
+			addr_bytes[acycle++] = (column >> 8) & 0xff;
+	}
+
+	if (page_addr != -1) {
+		addr_bytes[acycle++] = page_addr & 0xff;
+		addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
+		if (chip->chipsize > (128 << 20))
+			addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
+	}
+
+	if (acycle > 4)
+		*cycle0 = addr_bytes[index++];
+
+	for (bit_shift = 0; index < acycle; bit_shift += 8)
+		*addr1234 += addr_bytes[index++] << bit_shift;
+
+	return acycle << 19;	/* return acycle in cmd register */
+}
+
+static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
+				int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	unsigned long timeout;
+	unsigned int nfc_addr_cmd = 0;
+
+	unsigned int cmd1 = command << 2;
+
+	/* Set default settings: no cmd2, no addr cycle. read from nand */
+	unsigned int cmd2 = 0;
+	unsigned int vcmd2 = 0;
+	int acycle = NFCADDR_CMD_ACYCLE_NONE;
+	int csid = NFCADDR_CMD_CSID_3;
+	int dataen = NFCADDR_CMD_DATADIS;
+	int nfcwr = NFCADDR_CMD_NFCRD;
+	unsigned int addr1234 = 0;
+	unsigned int cycle0 = 0;
+	bool do_addr = true;
+
+	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
+	     __func__, command, column, page_addr);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
+		nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+		udelay(chip->chip_delay);
+
+		nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
+		timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
+			if (time_after(jiffies, timeout)) {
+				dev_err(host->dev,
+					"Time out to wait status ready!\n");
+				break;
+			}
+		}
+		return;
+	case NAND_CMD_STATUS:
+		do_addr = false;
+		break;
+	case NAND_CMD_PARAM:
+	case NAND_CMD_READID:
+		do_addr = false;
+		acycle = NFCADDR_CMD_ACYCLE_1;
+		if (column != -1)
+			addr1234 = column;
+		break;
+	case NAND_CMD_RNDOUT:
+		cmd2 = NAND_CMD_RNDOUTSTART << 10;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		if (command == NAND_CMD_READOOB) {
+			column += mtd->writesize;
+			command = NAND_CMD_READ0; /* only READ0 is valid */
+			cmd1 = command << 2;
+		}
+
+		cmd2 = NAND_CMD_READSTART << 10;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	/* For prgramming command, the cmd need set to write enable */
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
+		nfcwr = NFCADDR_CMD_NFCWR;
+		break;
+	default:
+		break;
+	}
+
+	if (do_addr)
+		acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
+				&cycle0);
+
+	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
+	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+
+	/*
+	 * Program and erase have their own busy handlers status, sequential
+	 * in, and deplete1 need no delay.
+	 */
+	switch (command) {
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_RNDIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_RNDOUT:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_READID:
+		return;
+
+	case NAND_CMD_READ0:
+		/* fall through */
+	default:
+		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
+	}
+}
+
+static struct platform_driver atmel_nand_nfc_driver;
 /*
  * Probe for the NAND device.
  */
@@ -1462,7 +1765,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	struct nand_chip *nand_chip;
 	struct resource *mem;
 	struct mtd_part_parser_data ppdata = {};
-	int res;
+	int res, irq;
 	struct pinctrl *pinctrl;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1478,6 +1781,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	res = platform_driver_register(&atmel_nand_nfc_driver);
+	if (res)
+		printk(KERN_ERR "atmel_nand: can't register NFC driver\n");
+
 	host->io_base = devm_request_and_ioremap(&pdev->dev, mem);
 	if (host->io_base == NULL) {
 		printk(KERN_ERR "atmel_nand: ioremap failed\n");
@@ -1505,7 +1812,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	/* Set address of NAND IO lines */
 	nand_chip->IO_ADDR_R = host->io_base;
 	nand_chip->IO_ADDR_W = host->io_base;
-	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
 	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
 	if (IS_ERR(pinctrl)) {
@@ -1514,44 +1820,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		goto err_nand_ioremap;
 	}
 
-	if (gpio_is_valid(host->board.rdy_pin)) {
-		res = devm_gpio_request(&pdev->dev,
-				host->board.rdy_pin, "nand_rdy");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
-
-		res = gpio_direction_input(host->board.rdy_pin);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request input direction rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
+	if (nand_nfc.is_initialized) {
+		/* NFC driver is probed and initialized */
+		host->nfc = &nand_nfc;
 
-		nand_chip->dev_ready = atmel_nand_device_ready;
-	}
+		nand_chip->select_chip = nfc_select_chip;
+		nand_chip->dev_ready = nfc_device_ready;
+		nand_chip->cmdfunc = nfc_nand_command;
 
-	if (gpio_is_valid(host->board.enable_pin)) {
-		res = devm_gpio_request(&pdev->dev,
-				host->board.enable_pin, "nand_enable");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request enable gpio %d\n",
-				host->board.enable_pin);
+		/* Initialize the interrupt for NFC */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(host->dev, "Cannot get HSMC irq!\n");
 			goto err_nand_ioremap;
 		}
 
-		res = gpio_direction_output(host->board.enable_pin, 1);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request output direction enable gpio %d\n",
-				host->board.enable_pin);
+		res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+				0, "hsmc", host);
+		if (res) {
+			dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+				irq);
 			goto err_nand_ioremap;
 		}
+	} else {
+		res = atmel_nand_set_enable_ready_pins(mtd);
+		if (res)
+			goto err_nand_ioremap;
+
+		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 
 	nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1656,6 +1952,7 @@ err_no_card:
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 err_nand_ioremap:
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 	return res;
 }
 
@@ -1680,6 +1977,8 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
+	platform_driver_unregister(&atmel_nand_nfc_driver);
+
 	return 0;
 }
 
@@ -1692,6 +1991,51 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+	struct atmel_nfc *nfc = &nand_nfc;
+	struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+	nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+	if (IS_ERR(nfc->base_cmd_regs))
+		return PTR_ERR(nfc->base_cmd_regs);
+
+	nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+	if (IS_ERR(nfc->hsmc_regs))
+		return PTR_ERR(nfc->hsmc_regs);
+
+	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (nfc_sram) {
+		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
+		if (IS_ERR(nfc->sram_bank0))
+			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+					PTR_ERR(nfc->sram_bank0));
+		else
+			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+	}
+
+	nfc->is_initialized = true;
+
+	dev_info(&pdev->dev, "NFC is probed.\n");
+	return 0;
+}
+
+static struct of_device_id atmel_nand_nfc_match[] = {
+	{ .compatible = "atmel,sama5d3-nfc" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver atmel_nand_nfc_driver = {
+	.driver = {
+		.name = "atmel_nand_nfc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_nand_nfc_match),
+	},
+	.probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
new file mode 100644
index 0000000..1b98ec6
--- /dev/null
+++ b/drivers/mtd/nand/atmel_nand_nfc.h
@@ -0,0 +1,94 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * ? Copyright 2013 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG	0x00		/* NFC Configuration Register */
+#define		NFC_CFG_PAGESIZE	(7 << 0)
+#define			NFC_CFG_PAGESIZE_512	(0 << 0)
+#define			NFC_CFG_PAGESIZE_1024	(1 << 0)
+#define			NFC_CFG_PAGESIZE_2048	(2 << 0)
+#define			NFC_CFG_PAGESIZE_4096	(3 << 0)
+#define			NFC_CFG_PAGESIZE_8192	(4 << 0)
+#define		NFC_CFG_WSPARE		(1 << 8)
+#define		NFC_CFG_RSPARE		(1 << 9)
+#define		NFC_CFG_NFC_DTOCYC	(0xf << 16)
+#define		NFC_CFG_NFC_DTOMUL	(0x7 << 20)
+#define		NFC_CFG_NFC_SPARESIZE	(0x7f << 24)
+
+#define ATMEL_HSMC_NFC_CTRL	0x04		/* NFC Control Register */
+#define		NFC_CTRL_ENABLE		(1 << 0)
+#define		NFC_CTRL_DISABLE	(1 << 1)
+
+#define ATMEL_HSMC_NFC_SR	0x08		/* NFC Status Register */
+#define		NFC_SR_XFR_DONE		(1 << 16)
+#define		NFC_SR_CMD_DONE		(1 << 17)
+#define		NFC_SR_RB_EDGE		(1 << 24)
+
+#define ATMEL_HSMC_NFC_IER	0x0c
+#define ATMEL_HSMC_NFC_IDR	0x10
+#define ATMEL_HSMC_NFC_IMR	0x14
+#define ATMEL_HSMC_NFC_CYCLE0	0x18		/* NFC Address Cycle Zero */
+#define		ATMEL_HSMC_NFC_ADDR_CYCLE0	(0xff)
+
+#define ATMEL_HSMC_NFC_BANK	0x1c		/* NFC Bank Register */
+#define		ATMEL_HSMC_NFC_BANK0		(0 << 0)
+#define		ATMEL_HSMC_NFC_BANK1		(1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+	writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+	readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1	(0xff << 2)	/* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD2	(0xff << 10)	/* Command for Cycle 2 */
+#define NFCADDR_CMD_VCMD2	(0x1 << 18)	/* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE	(0x7 << 19)	/* Number of Address required */
+#define		NFCADDR_CMD_ACYCLE_NONE		(0x0 << 19)
+#define		NFCADDR_CMD_ACYCLE_1		(0x1 << 19)
+#define		NFCADDR_CMD_ACYCLE_2		(0x2 << 19)
+#define		NFCADDR_CMD_ACYCLE_3		(0x3 << 19)
+#define		NFCADDR_CMD_ACYCLE_4		(0x4 << 19)
+#define		NFCADDR_CMD_ACYCLE_5		(0x5 << 19)
+#define NFCADDR_CMD_CSID	(0x7 << 22)	/* Chip Select Identifier */
+#define		NFCADDR_CMD_CSID_0		(0x0 << 22)
+#define		NFCADDR_CMD_CSID_1		(0x1 << 22)
+#define		NFCADDR_CMD_CSID_2		(0x2 << 22)
+#define		NFCADDR_CMD_CSID_3		(0x3 << 22)
+#define		NFCADDR_CMD_CSID_4		(0x4 << 22)
+#define		NFCADDR_CMD_CSID_5		(0x5 << 22)
+#define		NFCADDR_CMD_CSID_6		(0x6 << 22)
+#define		NFCADDR_CMD_CSID_7		(0x7 << 22)
+#define NFCADDR_CMD_DATAEN	(0x1 << 25)	/* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS	(0x0 << 25)	/* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD	(0x0 << 26)	/* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR	(0x1 << 26)	/* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY	(0x1 << 27)	/* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+	writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+	readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS		100
+#define	NFC_SRAM_BANK1_OFFSET	0x1200
+
+#endif
-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:52 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:52 +0800
Subject: [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) read
 data via sram
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-5-git-send-email-josh.wu@atmel.com>

NFC has embedded sram which can use to transfer data. This patch enable reading
nand flash via NFC SRAM. It will minimize the CPU overhead.

This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
mtd-utils.

Here puts the part of mtd_speedtest (read test) result as following:
Compare with non-NFC mtd_speedtest result, reading will reduce %45 cpu load
with increase %80 speed.

- commands use to test:
  # insmod /mnt/mtd_speedtest.ko dev=2 &
  # top -n 30 -d 1 | grep speedtest

- test result:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock read speed
  509   495 root     D     1164   0%  28% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  26% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 9403 KiB/s
mtd_speedtest: testing page read speed
  509   495 root     R     1164   0%  31% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  57% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  53% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  71% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 9258 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v2 --> v3:
  - if NFC sram address and size is specified then enable NFC sram read.
    Otherwise disable NFC sram read.

 drivers/mtd/nand/atmel_nand.c |  163 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 157 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index bf3370b..c2ec740 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -96,9 +96,13 @@ struct atmel_nfc {
 	void __iomem		*hsmc_regs;
 	void __iomem		*sram_bank0;
 	dma_addr_t		sram_bank0_phys;
+	bool			use_nfc_sram;
 
 	bool			is_initialized;
 	struct completion	comp_nfc;
+
+	/* Point to the sram bank which include readed data via NFC */
+	void __iomem		*data_in_sram;
 };
 static struct atmel_nfc	nand_nfc;
 
@@ -251,24 +255,47 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
 			return res;
 		}
 	}
+
 	return res;
 }
 
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+	int i;
+	u32 *t = trg;
+	const __iomem u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		*t++ = readl_relaxed(s++);
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 {
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
-	__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	}
 }
 
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 {
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
-	__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	}
 }
 
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
@@ -290,6 +317,40 @@ static void dma_complete_func(void *completion)
 	complete(completion);
 }
 
+static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
+{
+	/* NFC only has two banks. Must be 0 or 1 */
+	if (bank > 1)
+		return -EINVAL;
+
+	if (bank) {
+		/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
+		if (host->mtd.writesize > 2048)
+			return -EINVAL;
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
+	} else {
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
+	}
+
+	return 0;
+}
+
+static uint nfc_get_sram_off(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return NFC_SRAM_BANK1_OFFSET;
+	else
+		return 0;
+}
+
+static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
+	else
+		return host->nfc->sram_bank0_phys;
+}
+
 static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 			       int is_read)
 {
@@ -303,6 +364,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	void *p = buf;
 	int err = -EIO;
 	enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	struct atmel_nfc *nfc = host->nfc;
 
 	if (buf >= high_memory)
 		goto err_buf;
@@ -319,7 +381,12 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	}
 
 	if (is_read) {
-		dma_src_addr = host->io_phys;
+		if (nfc && nfc->data_in_sram)
+			dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
+				- (nfc->sram_bank0 + nfc_get_sram_off(host)));
+		else
+			dma_src_addr = host->io_phys;
+
 		dma_dst_addr = phys_addr;
 	} else {
 		dma_src_addr = phys_addr;
@@ -346,6 +413,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	dma_async_issue_pending(host->dma_chan);
 	wait_for_completion(&host->comp);
 
+	if (is_read && nfc && nfc->data_in_sram)
+		/* After read data from SRAM, need to increase the position */
+		nfc->data_in_sram += len;
+
 	err = 0;
 
 err_dma:
@@ -856,7 +927,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	unsigned long end_time;
 	int bitflips = 0;
 
-	pmecc_enable(host, NAND_ECC_READ);
+	if (!host->nfc || !host->nfc->use_nfc_sram)
+		pmecc_enable(host, NAND_ECC_READ);
 
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
@@ -1669,6 +1741,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	unsigned int addr1234 = 0;
 	unsigned int cycle0 = 0;
 	bool do_addr = true;
+	host->nfc->data_in_sram = NULL;
 
 	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
 	     __func__, command, column, page_addr);
@@ -1710,6 +1783,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 			command = NAND_CMD_READ0; /* only READ0 is valid */
 			cmd1 = command << 2;
 		}
+		if (host->nfc->use_nfc_sram) {
+			/* Enable Data transfer to sram */
+			dataen = NFCADDR_CMD_DATAEN;
+
+			/* Need enable PMECC now, since NFC will transfer
+			 * data in bus after sending nfc read command.
+			 */
+			if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+				pmecc_enable(host, NAND_ECC_READ);
+		}
 
 		cmd2 = NAND_CMD_READSTART << 10;
 		vcmd2 = NFCADDR_CMD_VCMD2;
@@ -1731,6 +1814,10 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
 	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
 
+	if (dataen == NFCADDR_CMD_DATAEN)
+		if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
+			dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
+
 	/*
 	 * Program and erase have their own busy handlers status, sequential
 	 * in, and deplete1 need no delay.
@@ -1748,12 +1835,65 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 		return;
 
 	case NAND_CMD_READ0:
+		if (dataen == NFCADDR_CMD_DATAEN) {
+			host->nfc->data_in_sram = host->nfc->sram_bank0 +
+				nfc_get_sram_off(host);
+			return;
+		}
 		/* fall through */
 	default:
 		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
 	}
 }
 
+static int nfc_sram_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	/* Initialize the NFC CFG register */
+	unsigned int cfg_nfc = 0;
+
+	/* set page size and oob layout */
+	switch (mtd->writesize) {
+	case 512:
+		cfg_nfc = NFC_CFG_PAGESIZE_512;
+		break;
+	case 1024:
+		cfg_nfc = NFC_CFG_PAGESIZE_1024;
+		break;
+	case 2048:
+		cfg_nfc = NFC_CFG_PAGESIZE_2048;
+		break;
+	case 4096:
+		cfg_nfc = NFC_CFG_PAGESIZE_4096;
+		break;
+	case 8192:
+		cfg_nfc = NFC_CFG_PAGESIZE_8192;
+		break;
+	default:
+		dev_err(host->dev, "Unsupported page size for NFC.\n");
+		res = -ENXIO;
+		return res;
+	}
+
+	/* oob bytes size = (NFCSPARESIZE + 1) * 4
+	 * Max support spare size is 512 bytes. */
+	cfg_nfc |= (((mtd->oobsize / 4) - 1) << 24 & NFC_CFG_NFC_SPARESIZE);
+	/* default set a max timeout */
+	cfg_nfc |= NFC_CFG_RSPARE |
+			NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
+
+	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
+
+	nfc_set_sram_bank(host, 0);
+
+	dev_info(host->dev, "Using NFC Sram read\n");
+
+	return 0;
+}
+
 static struct platform_driver atmel_nand_nfc_driver;
 /*
  * Probe for the NAND device.
@@ -1928,6 +2068,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			goto err_hw_ecc;
 	}
 
+	/* initialize the nfc configuration register */
+	if (host->nfc && host->nfc->use_nfc_sram) {
+		res = nfc_sram_init(mtd);
+		if (res) {
+			host->nfc->use_nfc_sram = false;
+			dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
+		}
+	}
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		res = -ENXIO;
@@ -2009,11 +2158,13 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
 	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	if (nfc_sram) {
 		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
-		if (IS_ERR(nfc->sram_bank0))
+		if (IS_ERR(nfc->sram_bank0)) {
 			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
 					PTR_ERR(nfc->sram_bank0));
-		else
+		} else {
+			nfc->use_nfc_sram = true;
 			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+		}
 	}
 
 	nfc->is_initialized = true;
-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:53 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:53 +0800
Subject: [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) write
 via sram
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-6-git-send-email-josh.wu@atmel.com>

This patch enable writing nand flash via NFC SRAM. It will minimize the CPU
overhead. The SRAM write only support ECC_NONE and ECC_HW with PMECC.

To enable this NFC write by SRAM feature, you can add a string in dts under
NFC driver node.

This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
mtd-utils.

Here is part of mtd_speedtest (writing test) result, compare with non-NFC
writing, it reduces %65 cpu load with loss %12 speed.

- commands use to test:
  # insmod /mnt/mtd_speedtest.ko dev=2 &
  # top -n 30 -d 1 | grep speedtest

- test result:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock write speed
  509   495 root     D     1164   0%   7% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%   8% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%   5% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5194 KiB/s
mtd_speedtest: testing page write speed
  509   495 root     D     1164   0%  32% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  27% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  30% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5024 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v2 --> v3:
  - use a property of NFC node to enable/disable NFC write via sram.

 .../devicetree/bindings/mtd/atmel-nand.txt         |    2 +
 drivers/mtd/nand/atmel_nand.c                      |  107 ++++++++++++++++++--
 2 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index 6a267cb..da78e22 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -35,6 +35,8 @@ Optional properties:
     - reg : should specify the address and size used for NFC command registers,
             NFC registers and NFC Sram. NFC Sram address and size can be absent
             if don't want to use it.
+  - Optional properties:
+    - atmel,write-by-sram: boolean to enable NFC write by sram.
 
 Examples:
 nand0: nand at 40000000,0 {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index c2ec740..e3e348b 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -97,12 +97,14 @@ struct atmel_nfc {
 	void __iomem		*sram_bank0;
 	dma_addr_t		sram_bank0_phys;
 	bool			use_nfc_sram;
+	bool			write_by_sram;
 
 	bool			is_initialized;
 	struct completion	comp_nfc;
 
 	/* Point to the sram bank which include readed data via NFC */
 	void __iomem		*data_in_sram;
+	bool			will_write_sram;
 };
 static struct atmel_nfc	nand_nfc;
 
@@ -269,6 +271,16 @@ static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
 		*t++ = readl_relaxed(s++);
 }
 
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+	int i;
+	u32 __iomem *t = trg;
+	const u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		writel_relaxed(*s++, t++);
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -390,7 +402,11 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 		dma_dst_addr = phys_addr;
 	} else {
 		dma_src_addr = phys_addr;
-		dma_dst_addr = host->io_phys;
+
+		if (nfc && nfc->write_by_sram)
+			dma_dst_addr = nfc_sram_phys(host);
+		else
+			dma_dst_addr = host->io_phys;
 	}
 
 	tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
@@ -961,9 +977,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 	int i, j;
 	unsigned long end_time;
 
-	pmecc_enable(host, NAND_ECC_WRITE);
-
-	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	if (!host->nfc || !host->nfc->write_by_sram) {
+		pmecc_enable(host, NAND_ECC_WRITE);
+		chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	}
 
 	end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
 	while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
@@ -1802,6 +1819,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_RNDIN:
 		nfcwr = NFCADDR_CMD_NFCWR;
+		if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
+			dataen = NFCADDR_CMD_DATAEN;
 		break;
 	default:
 		break;
@@ -1846,6 +1865,68 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	}
 }
 
+static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t offset, int data_len, const uint8_t *buf,
+			int oob_required, int page, int cached, int raw)
+{
+	int cfg, len;
+	int status = 0;
+	struct atmel_nand_host *host = chip->priv;
+	void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
+
+	/* Subpage write is not supported */
+	if (offset || (data_len < mtd->writesize))
+		return -EINVAL;
+
+	cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
+	len = mtd->writesize;
+
+	if (unlikely(raw)) {
+		len += mtd->oobsize;
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
+	} else
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
+
+	/* Copy page data to sram that will write to nand via NFC */
+	if (use_dma) {
+		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
+			/* Fall back to use cpu copy */
+			memcpy32_toio(sram, buf, len);
+	} else {
+		memcpy32_toio(sram, buf, len);
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+		/*
+		 * When use NFC sram, need set up PMECC before send
+		 * NAND_CMD_SEQIN command. Since when the nand command
+		 * is sent, nfc will do transfer from sram and nand.
+		 */
+		pmecc_enable(host, NAND_ECC_WRITE);
+
+	host->nfc->will_write_sram = true;
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+	host->nfc->will_write_sram = false;
+
+	if (likely(!raw))
+		/* Need to write ecc into oob */
+		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+	if (status < 0)
+		return status;
+
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
+
+	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+		status = chip->errstat(mtd, chip, FL_WRITING, status, page);
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
 static int nfc_sram_init(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd->priv;
@@ -1887,10 +1968,20 @@ static int nfc_sram_init(struct mtd_info *mtd)
 
 	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
 
+	host->nfc->will_write_sram = false;
 	nfc_set_sram_bank(host, 0);
 
-	dev_info(host->dev, "Using NFC Sram read\n");
+	/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
+	if (host->nfc->write_by_sram) {
+		if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
+				chip->ecc.mode == NAND_ECC_NONE)
+			chip->write_page = nfc_sram_write_page;
+		else
+			host->nfc->write_by_sram = false;
+	}
 
+	dev_info(host->dev, "Using NFC Sram read %s\n",
+			host->nfc->write_by_sram ? "and write" : "");
 	return 0;
 }
 
@@ -2164,11 +2255,15 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
 		} else {
 			nfc->use_nfc_sram = true;
 			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+
+			if (pdev->dev.of_node)
+				nfc->write_by_sram = of_property_read_bool(
+						pdev->dev.of_node,
+						"atmel,write-by-sram");
 		}
 	}
 
 	nfc->is_initialized = true;
-
 	dev_info(&pdev->dev, "NFC is probed.\n");
 	return 0;
 }
-- 
1.7.9.5



From josh.wu at atmel.com  Mon Jun 10 06:26:54 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Mon, 10 Jun 2013 18:26:54 +0800
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1370860014-1770-7-git-send-email-josh.wu@atmel.com>

If the child node has compatible property then it is a driver not partition.

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
 drivers/mtd/ofpart.c |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 553d6d6..61ce1f8 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -20,6 +20,10 @@
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 
+static bool node_has_compatible(struct device_node *pp, int *len)
+{
+	return of_get_property(pp, "compatible", len);
+}
 static int parse_ofpart_partitions(struct mtd_info *master,
 				   struct mtd_partition **pparts,
 				   struct mtd_part_parser_data *data)
@@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 	/* First count the subnodes */
 	pp = NULL;
 	nr_parts = 0;
-	while ((pp = of_get_next_child(node, pp)))
+	while ((pp = of_get_next_child(node, pp))) {
+		int len;
+		if (node_has_compatible(pp, &len))
+			continue;
+
 		nr_parts++;
+	}
 
 	if (nr_parts == 0)
 		return 0;
@@ -57,6 +66,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 		int len;
 		int a_cells, s_cells;
 
+		if (node_has_compatible(pp, &len))
+			continue;
+
 		reg = of_get_property(pp, "reg", &len);
 		if (!reg) {
 			nr_parts--;
-- 
1.7.9.5



From emilgoode at gmail.com  Mon Jun 10 06:35:37 2013
From: emilgoode at gmail.com (Emil Goode)
Date: Mon, 10 Jun 2013 12:35:37 +0200
Subject: [PATCH v2] mtd: orion_nand: Improve error handling in
 orion_nand_probe
In-Reply-To: <001e01ce659c$3e582270$bb086750$@samsung.com>
References: <1370822442-25217-1-git-send-email-emilgoode@gmail.com>
 <001e01ce659c$3e582270$bb086750$@samsung.com>
Message-ID: <20130610103537.GA20987@debian>

Hello Jingoo,

Thank you for the review. There was another discussion and the following
patch was sent that converts printk to dev_err.

http://lists.infradead.org/pipermail/linux-mtd/2013-June/047198.html

My conclusion of the discussion was that error messages for kzalloc
calls are probably made out of habit and that it's better to rely on
the internal error messages of kzalloc.

http://lists.infradead.org/pipermail/linux-mtd/2013-June/047203.html

So instead of sending a second version that applies on top of the
"convert printk to dev_*" patch, I decided to remove the error
messages for the kzalloc calls.

About the introduced call to devm_request_mem_region that is made
inside of devm_ioremap_resource. My understanding is that
request_mem_region should be used for all memory mappen I/O to
inform the kernel of the I/O adress range that will be used by
the driver.

There are other examples in drivers/mtd/nand of devm_ioremap_resource
beeing used in probe functions.

Here are some of them:
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/davinci_nand.c

Best regards,

Emil

On Mon, Jun 10, 2013 at 02:34:57PM +0900, Jingoo Han wrote:
> Monday, June 10, 2013 9:01 AM, Emil Goode wrote:
> > 
> > This patch fixes some issues in the error handling and simplifies
> > the code by converting to devm* functions.
> > 
> > If the kzalloc call fails it is unnecessary to use the label no_res
> > and pass a NULL pointer to kfree. If the devm_kzalloc call fails on
> > line 110 we forget to call iounmap for the previous ioremap call.
> > 
> > The following changes are introduced:
> > - Convert to devm_kzalloc and remove calls to kfree.
> > - Convert to devm_ioremap_resource that adds a missing call to
> >   *request_mem_region and remove calls to iounmap.
> > - The devm_ioremap_resource function checks the passed resource so
> >   we can remove the NULL check after the platform_get_resource call.
> > 
> > Signed-off-by: Emil Goode <emilgoode at gmail.com>
> > ---
> > This patch is only build tested
> > v2: Fix change log typo and remove error messages for kzalloc calls
> > 
> >  drivers/mtd/nand/orion_nand.c |   49 +++++++++++++----------------------------
> >  1 file changed, 15 insertions(+), 34 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
> > index 8fbd002..76b9fba 100644
> > --- a/drivers/mtd/nand/orion_nand.c
> > +++ b/drivers/mtd/nand/orion_nand.c
> > @@ -85,35 +85,24 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> >  	int ret = 0;
> >  	u32 val = 0;
> > 
> > -	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
> > -	if (!nc) {
> > -		printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
> 
> CC'ed Dan Carpenter, Andy Shevchenko
> 
> You don't need to remove this error message.
> You would replace 'printk(KERN_ERR "orion_nand:...)' with
> 'dev_err(&pdev->dev,)'.
> 
> 	dev_err("failed to allocate device structure.\n");
> 
> 
> > -		ret = -ENOMEM;
> > -		goto no_res;
> > -	}
> > +	nc = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip) +
> > +			  sizeof(struct mtd_info), GFP_KERNEL);
> > +	if (!nc)
> > +		return -ENOMEM;
> > +
> >  	mtd = (struct mtd_info *)(nc + 1);
> > 
> >  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > -	if (!res) {
> > -		ret = -ENODEV;
> > -		goto no_res;
> > -	}
> > -
> > -	io_base = ioremap(res->start, resource_size(res));
> > -	if (!io_base) {
> > -		printk(KERN_ERR "orion_nand: ioremap failed\n");
> 
> Yes, this error message is not necessary.
> devm_ioremap_resource() provides its own error messages; so all
> explicit error messages can be removed from the failure code paths.
> 
> 
> > -		ret = -EIO;
> > -		goto no_res;
> > -	}
> > +	io_base = devm_ioremap_resource(&pdev->dev, res);
> 
> How about using devm_ioremap() instead of devm_ioremap_resource()?
> 
> Only ioremap() was used previously; however, devm_ioremap_resource()
> internally calls both devm_request_mem_region() and devm_ioremap().
> 
> If it is wrong, please let me know kindly. :)
> 
> 
> > +	if (IS_ERR(io_base))
> > +		return PTR_ERR(io_base);
> > 
> >  	if (pdev->dev.of_node) {
> >  		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
> > -					GFP_KERNEL);
> > -		if (!board) {
> > -			printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
> 
> As above mentioned, you don't need to remove this error message.
> You would replace 'printk(KERN_ERR "orion_nand:...)' with
> 'dev_err(&pdev->dev,)'.
> 
> 	dev_err("failed to allocate board structure.\n");
> 
> 
> Best regards,
> Jingoo Han
> 
> 
> > -			ret = -ENOMEM;
> > -			goto no_res;
> > -		}
> > +				     GFP_KERNEL);
> > +		if (!board)
> > +			return -ENOMEM;
> > +
> >  		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
> >  			board->cle = (u8)val;
> >  		else
> > @@ -167,7 +156,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> > 
> >  	if (nand_scan(mtd, 1)) {
> >  		ret = -ENXIO;
> > -		goto no_dev;
> > +		goto disable_clk;
> >  	}
> > 
> >  	mtd->name = "orion_nand";
> > @@ -176,20 +165,17 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> >  			board->parts, board->nr_parts);
> >  	if (ret) {
> >  		nand_release(mtd);
> > -		goto no_dev;
> > +		goto disable_clk;
> >  	}
> > 
> >  	return 0;
> > 
> > -no_dev:
> > +disable_clk:
> >  	if (!IS_ERR(clk)) {
> >  		clk_disable_unprepare(clk);
> >  		clk_put(clk);
> >  	}
> >  	platform_set_drvdata(pdev, NULL);
> > -	iounmap(io_base);
> > -no_res:
> > -	kfree(nc);
> > 
> >  	return ret;
> >  }
> > @@ -197,15 +183,10 @@ no_res:
> >  static int orion_nand_remove(struct platform_device *pdev)
> >  {
> >  	struct mtd_info *mtd = platform_get_drvdata(pdev);
> > -	struct nand_chip *nc = mtd->priv;
> >  	struct clk *clk;
> > 
> >  	nand_release(mtd);
> > 
> > -	iounmap(nc->IO_ADDR_W);
> > -
> > -	kfree(nc);
> > -
> >  	clk = clk_get(&pdev->dev, NULL);
> >  	if (!IS_ERR(clk)) {
> >  		clk_disable_unprepare(clk);
> > --
> > 1.7.10.4
> 


From sergei.shtylyov at cogentembedded.com  Mon Jun 10 08:35:25 2013
From: sergei.shtylyov at cogentembedded.com (Sergei Shtylyov)
Date: Mon, 10 Jun 2013 16:35:25 +0400
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
Message-ID: <51B5C80D.2030303@cogentembedded.com>

hello.

On 10-06-2013 14:26, Josh Wu wrote:

> If the child node has compatible property then it is a driver not partition.

> Signed-off-by: Josh Wu <josh.wu at atmel.com>
> ---
>   drivers/mtd/ofpart.c |   14 +++++++++++++-
>   1 file changed, 13 insertions(+), 1 deletion(-)


> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index 553d6d6..61ce1f8 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
[...]
> @@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>   	/* First count the subnodes */
>   	pp = NULL;
>   	nr_parts = 0;
> -	while ((pp = of_get_next_child(node, pp)))
> +	while ((pp = of_get_next_child(node, pp))) {

    Assignment in *while*? Is scripts/checkpatch.pl happy about that?

> +		int len;

    Empty line wouldn't hurt here, after declaration.

> +		if (node_has_compatible(pp, &len))
> +			continue;
> +
>   		nr_parts++;
> +	}
>
>   	if (nr_parts == 0)
>   		return 0;

WBR, Sergei



From plagnioj at jcrosoft.com  Mon Jun 10 09:22:11 2013
From: plagnioj at jcrosoft.com (Jean-Christophe PLAGNIOL-VILLARD)
Date: Mon, 10 Jun 2013 15:22:11 +0200
Subject: [PATCH 3/6] mtd: atmel_nand: add Nand Flash Controller (NFC)
 support
In-Reply-To: <1370860014-1770-4-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-4-git-send-email-josh.wu@atmel.com>
Message-ID: <20130610132211.GO23653@game.jcrosoft.org>

> +
>  /*
>   * Minimal-overhead PIO for data access.
>   */
> @@ -1341,6 +1409,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
>  
>  	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
>  
> +	/* load the nfc driver if there is */
> +	of_platform_populate(np, NULL, NULL, host->dev);

what is this?????


> +
>  	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
>  		return 0;	/* Not using PMECC */
>  
> @@ -1452,6 +1523,238 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
>  	return 0;
>  }
>  
> +/* SMC interrupt service routine */
> +static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
> +{
> +	struct atmel_nand_host *host = dev_id;
> +	u32 status, mask, pending;
> +	irqreturn_t ret = IRQ_HANDLED;
> +
> +	status = nfc_readl(host->nfc->hsmc_regs, SR);
> +	mask = nfc_readl(host->nfc->hsmc_regs, IMR);
> +	pending = status & mask;
> +
> +	if (pending & NFC_SR_XFR_DONE) {
> +		complete(&host->nfc->comp_nfc);
> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
> +	} else if (pending & NFC_SR_RB_EDGE) {
> +		complete(&host->nfc->comp_nfc);
> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
> +	} else if (pending & NFC_SR_CMD_DONE) {
> +		complete(&host->nfc->comp_nfc);
> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
> +	} else {
> +		ret = IRQ_NONE;
> +	}
> +
> +	return ret;
> +}
> +
> +/* NFC(Nand Flash Controller) related functions */
> +static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
> +{
> +	unsigned long timeout;
> +	init_completion(&host->nfc->comp_nfc);
> +
> +	/* Enable interrupt that need to wait for */
> +	nfc_writel(host->nfc->hsmc_regs, IER, flag);
> +
> +	timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
> +			msecs_to_jiffies(NFC_TIME_OUT_MS));
> +	if (timeout)
> +		return 0;
> +
> +	/* Time out to wait for the interrupt */
> +	dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
> +	return -ETIMEDOUT;
> +}
> +
> +static int nfc_send_command(struct atmel_nand_host *host,
> +	unsigned int cmd, unsigned int addr, unsigned char cycle0)
> +{
> +	unsigned long timeout;
> +	dev_dbg(host->dev,
> +		"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
> +		cmd, addr, cycle0);
> +
> +	timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
> +	while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
> +			& NFCADDR_CMD_NFCBUSY) {
> +		if (time_after(jiffies, timeout)) {
> +			dev_err(host->dev,
> +				"Time out to wait CMD_NFCBUSY ready!\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +	nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
> +	nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
> +	return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
> +}
> +
> +static int nfc_device_ready(struct mtd_info *mtd)
> +{
> +	struct nand_chip *nand_chip = mtd->priv;
> +	struct atmel_nand_host *host = nand_chip->priv;
> +	if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
> +		return 1;
> +	return 0;
> +}
> +
> +static void nfc_select_chip(struct mtd_info *mtd, int chip)
> +{
> +	struct nand_chip *nand_chip = mtd->priv;
> +	struct atmel_nand_host *host = nand_chip->priv;
> +
> +	if (chip == -1)
> +		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
> +	else
> +		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
> +}
> +
> +static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
> +		unsigned int *addr1234, unsigned int *cycle0)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +
> +	int acycle = 0;
> +	unsigned char addr_bytes[8];
> +	int index = 0, bit_shift;
> +
> +	BUG_ON(addr1234 == NULL || cycle0 == NULL);
> +
> +	*cycle0 = 0;
> +	*addr1234 = 0;
> +
> +	if (column != -1) {
> +		if (chip->options & NAND_BUSWIDTH_16)
> +			column >>= 1;
> +		addr_bytes[acycle++] = column & 0xff;
> +		if (mtd->writesize > 512)
> +			addr_bytes[acycle++] = (column >> 8) & 0xff;
> +	}
> +
> +	if (page_addr != -1) {
> +		addr_bytes[acycle++] = page_addr & 0xff;
> +		addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
> +		if (chip->chipsize > (128 << 20))
> +			addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
> +	}
> +
> +	if (acycle > 4)
> +		*cycle0 = addr_bytes[index++];
> +
> +	for (bit_shift = 0; index < acycle; bit_shift += 8)
> +		*addr1234 += addr_bytes[index++] << bit_shift;
> +
> +	return acycle << 19;	/* return acycle in cmd register */
> +}
> +
> +static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
> +				int column, int page_addr)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct atmel_nand_host *host = chip->priv;
> +	unsigned long timeout;
> +	unsigned int nfc_addr_cmd = 0;
> +
> +	unsigned int cmd1 = command << 2;
> +
> +	/* Set default settings: no cmd2, no addr cycle. read from nand */
> +	unsigned int cmd2 = 0;
> +	unsigned int vcmd2 = 0;
> +	int acycle = NFCADDR_CMD_ACYCLE_NONE;
> +	int csid = NFCADDR_CMD_CSID_3;
> +	int dataen = NFCADDR_CMD_DATADIS;
> +	int nfcwr = NFCADDR_CMD_NFCRD;
> +	unsigned int addr1234 = 0;
> +	unsigned int cycle0 = 0;
> +	bool do_addr = true;
> +
> +	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
> +	     __func__, command, column, page_addr);
> +
> +	switch (command) {
> +	case NAND_CMD_RESET:
> +		nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
> +		nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
> +		udelay(chip->chip_delay);
> +
> +		nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
> +		timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
> +		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
> +			if (time_after(jiffies, timeout)) {
> +				dev_err(host->dev,
> +					"Time out to wait status ready!\n");
> +				break;
> +			}
> +		}
> +		return;
> +	case NAND_CMD_STATUS:
> +		do_addr = false;
> +		break;
> +	case NAND_CMD_PARAM:
> +	case NAND_CMD_READID:
> +		do_addr = false;
> +		acycle = NFCADDR_CMD_ACYCLE_1;
> +		if (column != -1)
> +			addr1234 = column;
> +		break;
> +	case NAND_CMD_RNDOUT:
> +		cmd2 = NAND_CMD_RNDOUTSTART << 10;
> +		vcmd2 = NFCADDR_CMD_VCMD2;
> +		break;
> +	case NAND_CMD_READ0:
> +	case NAND_CMD_READOOB:
> +		if (command == NAND_CMD_READOOB) {
> +			column += mtd->writesize;
> +			command = NAND_CMD_READ0; /* only READ0 is valid */
> +			cmd1 = command << 2;
> +		}
> +
> +		cmd2 = NAND_CMD_READSTART << 10;
> +		vcmd2 = NFCADDR_CMD_VCMD2;
> +		break;
> +	/* For prgramming command, the cmd need set to write enable */
> +	case NAND_CMD_PAGEPROG:
> +	case NAND_CMD_SEQIN:
> +	case NAND_CMD_RNDIN:
> +		nfcwr = NFCADDR_CMD_NFCWR;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (do_addr)
> +		acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
> +				&cycle0);
> +
> +	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
> +	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
> +
> +	/*
> +	 * Program and erase have their own busy handlers status, sequential
> +	 * in, and deplete1 need no delay.
> +	 */
> +	switch (command) {
> +	case NAND_CMD_CACHEDPROG:
> +	case NAND_CMD_PAGEPROG:
> +	case NAND_CMD_ERASE1:
> +	case NAND_CMD_ERASE2:
> +	case NAND_CMD_RNDIN:
> +	case NAND_CMD_STATUS:
> +	case NAND_CMD_RNDOUT:
> +	case NAND_CMD_SEQIN:
> +	case NAND_CMD_READID:
> +		return;
> +
> +	case NAND_CMD_READ0:
> +		/* fall through */
> +	default:
> +		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
> +	}
> +}
> +
> +static struct platform_driver atmel_nand_nfc_driver;
>  /*
>   * Probe for the NAND device.
>   */
> @@ -1462,7 +1765,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>  	struct nand_chip *nand_chip;
>  	struct resource *mem;
>  	struct mtd_part_parser_data ppdata = {};
> -	int res;
> +	int res, irq;
>  	struct pinctrl *pinctrl;
>  
>  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> @@ -1478,6 +1781,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> +	res = platform_driver_register(&atmel_nand_nfc_driver);
> +	if (res)
> +		printk(KERN_ERR "atmel_nand: can't register NFC driver\n");
> +

and this????
>  	host->io_base = devm_request_and_ioremap(&pdev->dev, mem);
>  	if (host->io_base == NULL) {
>  		printk(KERN_ERR "atmel_nand: ioremap failed\n");
> @@ -1505,7 +1812,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>  	/* Set address of NAND IO lines */
>  	nand_chip->IO_ADDR_R = host->io_base;
>  	nand_chip->IO_ADDR_W = host->io_base;
> -	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
>  
>  	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
>  	if (IS_ERR(pinctrl)) {
> @@ -1514,44 +1820,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>  		goto err_nand_ioremap;
>  	}
>  
Best Regards,
J.


From Anton.Prins at nl.bosch.com  Tue Jun 11 08:16:52 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Tue, 11 Jun 2013 14:16:52 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <1370239282.21714.21.camel@sauron.fi.intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>

Hi Artem,

We got logging inside the recovery procedure to print the 'orphan LEB' information.
I wonder if the LEB9 moves yes/no? So is it safe to use 'dd' with an offset of 9*LEB?
(Difficulty is we have no file system, so this was the first option...)

You see flood of message's; but I suppose the first part is the information required!
If not I have to make some solution to go for 'dd'.

Thanks in advance,

Anton


-------------- next part --------------
A non-text attachment was scrubbed...
Name: leb9dump-filtered.log
Type: application/octet-stream
Size: 328190 bytes
Desc: leb9dump-filtered.log
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130611/978b3d38/attachment-0001.obj>

From computersforpeace at gmail.com  Tue Jun 11 19:34:59 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Tue, 11 Jun 2013 16:34:59 -0700
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
Message-ID: <CAN8TOE-JuVAAKBR84cbs9Hge+bQ6hQpFyoSDywKvCMe7h+Lc4g@mail.gmail.com>

Hi Josh,

On Mon, Jun 10, 2013 at 3:26 AM, Josh Wu <josh.wu at atmel.com> wrote:
> If the child node has compatible property then it is a driver not partition.
>
> Signed-off-by: Josh Wu <josh.wu at atmel.com>
> ---
>  drivers/mtd/ofpart.c |   14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index 553d6d6..61ce1f8 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
> @@ -20,6 +20,10 @@
>  #include <linux/slab.h>
>  #include <linux/mtd/partitions.h>
>
> +static bool node_has_compatible(struct device_node *pp, int *len)
> +{
> +       return of_get_property(pp, "compatible", len);
> +}

The way the interface is named, it seems like a user only would ever
need the bool return value, not the implicit 'len' return value. So I
would write it like this:

static bool node_has_compatible(struct device_node *pp)
{
       return of_get_property(pp, "compatible", NULL);
}

>  static int parse_ofpart_partitions(struct mtd_info *master,
>                                    struct mtd_partition **pparts,
>                                    struct mtd_part_parser_data *data)
> @@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>         /* First count the subnodes */
>         pp = NULL;
>         nr_parts = 0;
> -       while ((pp = of_get_next_child(node, pp)))
> +       while ((pp = of_get_next_child(node, pp))) {
> +               int len;
> +               if (node_has_compatible(pp, &len))

Then this would just be:

if (node_has_compatible(pp))
...
etc. (rest snipped)

On a more important question, why does a NAND device node have
sub-nodes that are not partitions? And if such devices exist, wouldn't
it be more foolproof to establish a "compatible" property for ofpart
partitions? Of course, we'd still have to retain
backward-compatibility and allow partitions without a "compatible"
prop. But this question probably should be addressed in the commit log
and documented in Documentation/devicetree/bindings/mtd/partition.txt
; either specifying that all sub-nodes without a compatible property
must be partitions, or else some other explanation.

Brian


From Anton.Prins at nl.bosch.com  Wed Jun 12 03:12:34 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Wed, 12 Jun 2013 09:12:34 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <1370239282.21714.21.camel@sauron.fi.intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A32AE@SI-MBX14.de.bosch.com>

Hi Artem,

Hopefully you can find some time for some analysis on the LEB, I managed to dd LEB9.
It is attached! 

Thanks in advance,

Met vriendelijke groeten | Best Regards, 
Anton Prins

-----Original Message-----
From: Artem Bityutskiy [mailto:dedekind1 at gmail.com] 
Sent: maandag 3 juni 2013 8:01
To: Prins Anton (ST-CO/ENG1.1)
Cc: Jan Kara; Adrian Hunter; linux-mtd at lists.infradead.org
Subject: Re: UBIFS failure & stable page writes

On Fri, 2013-05-31 at 11:51 +0200, Prins Anton (ST-CO/ENG1.1) wrote:
> Hi Artem,
> 
> Some questions regarding this issue:
> - The orphan area is fixed size, in the implementation we unlink/delete a file 4 times a second... could there be any relation?
>   (How can we calculate the required orphan area size in LEBs?)

No, we stress-tested it with a lot more frequent deletions. I cannot
answer about size calculation off the top of my head, I'd need to read
the code and try calculating. But I guess it is easier to find this out
by writing a small test program which will create create/open/unlink
files until it fails. And you can experiment with amount of orphan LEBs
ans find all the numbers. You can also share them with us :-)

> - Initial the three file systems are programmed if 'flat-image' (ubinized and free space fix-up) from U-boot; can there be an issue?

There were several free space fix-up bug-fixes recently.

I wonder if you have these patches:

0c6c7fa1313fcb69cae35e34168d2e83b8da854a
fe96efc1a3c049f0a1bcd9b65e0faeb751ce5ec6

They prevent from unpleasant bugs in flashers - when you flash a new
image to a flash which alsready contains some UBI stuff, and flasher
does not erase some eraseblocks, the old contents may be treated as part
of the new image, causing really random and subtle problems.

>   (Every ubi-filesystem has its own MTD, so I guess partition separation is guaranteed by the MTD-layer).

Should be.

> - How can I find the orphan LEB(s), to send you some 'contents'?

The LEB numbers range is:

[c->orph_first, c->orph_last]

So all LEBs from c->orph_first to c->orph_last are orphan LEBs.

You can inject printk and print the numbers.

Then you can read the corresponding LEBs directly from /dev/ubiX_Y using
dd. You'll just need to calculate offsets. Offset is LEB number * LEB
size.

-- 
Best Regards,
Artem Bityutskiy

-------------- next part --------------
A non-text attachment was scrubbed...
Name: LEB9DUMP.BIN
Type: application/octet-stream
Size: 516096 bytes
Desc: LEB9DUMP.BIN
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130612/92bef671/attachment-0001.obj>

From sourav.poddar at ti.com  Wed Jun 12 03:30:16 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Wed, 12 Jun 2013 13:00:16 +0530
Subject: U-boot: Erase/read/write issue with S25fl256S flash device
Message-ID: <51B82388.2000909@ti.com>

Hi,

I am working on qspi flash device S25FL256S at u-boot level. I am trying to
make use of the existing spi_flash.c framework available at u-boot for 
erasing/reading/writing
into the flash device.

There are several issues(mentioned below), which I faced while using 
S25FL256s flash device
with my dra7xx board which has a qspi controller to which the above 
mentioned flash device is attached.

1. Erase (spi_flash_cmd_erase)

Issuing a command something like this..

sf erase 0x0 0x50000
  - erases only first 0x20000 bytes of flash device, anything above that 
is not erase. I need to
    issue separate commands after 0x20000 for every 0x10000 bytes.

Am i missing anything here?

2. read

sf read 81000000 0 0x10000

Read is not happening properly. The last few byte along the 4k boundary 
always shows zero.
Above 4k bytes, read is not happening.

For ex:
  DRA752 EVM # md 81000f00
81000f00: ffffffff ffffffff ffffffff ffffffff    ................
81000f10: ffffffff ffffffff ffffffff ffffffff    ................
81000f20: ffffffff ffffffff ffffffff ffffffff    ................
81000f30: ffffffff ffffffff ffffffff ffffffff    ................
81000f40: ffffffff ffffffff ffffffff ffffffff    ................
81000f50: ffffffff ffffffff ffffffff ffffffff    ................
81000f60: ffffffff ffffffff ffffffff ffffffff    ................
81000f70: ffffffff ffffffff ffffffff ffffffff    ................
81000f80: ffffffff ffffffff ffffffff ffffffff    ................
81000f90: ffffffff ffffffff ffffffff ffffffff    ................
81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
81000ff0: ffffffff ffffffff 00ffffff 00000000    ................

In this dump, if you see 81000ff0 the last column shows 000000 which is
not expected. and it happens along every 4k bytes.


So, to get rid of the above issue, I switched to page read with the 
below patch[1],
which is giving me the correct result.
[1]:
@@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash *flash, 
const u8 *cmd,
  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
                 size_t len, void *data)
  {
-       u8 cmd[5];
+       unsigned long page_addr, byte_addr, page_size;
+       size_t chunk_len, actual;
+       int ret = 0;
+       u8 cmd[4];

         /* Handle memory-mapped SPI */
         if (flash->memory_map)
                 memcpy(data, flash->memory_map + offset, len);
+       page_size = flash->page_size;
+       page_addr = offset / page_size;
+       byte_addr = offset % page_size;
+
+       cmd[0] = CMD_READ_ARRAY_SLOW;
+       for (actual = 0; actual < len; actual += chunk_len) {
+               chunk_len = min(len - actual, page_size - byte_addr);
+
+               cmd[1] = page_addr >> 8;
+               cmd[2] = page_addr;
+               cmd[3] = byte_addr;
+
+               ret = spi_flash_read_common(flash, cmd, sizeof(cmd), 
data + actual, chunk_len);
+               if (ret < 0) {
+                       debug("SF: read failed");
+                       break;
+               }

-       cmd[0] = CMD_READ_ARRAY_FAST;
-       spi_flash_addr(offset, cmd);
-       cmd[4] = 0x00;
+               byte_addr += chunk_len;
+               if (byte_addr == page_size) {
+                       page_addr++;
+                       byte_addr = 0;
+               }
+       }

-       return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
+       return ret;
  }

Any idea about this?

3.  write (spi_flash_cmd_write_multi)
   write not happening properly.

observations: only able to write single page, anything after a page is 
not getting
         written.
Workaround:
I did a write disable latch at the end of every write cycle(page 
program) and enable it
again for the next loop. With this, I see I get rid of the above issue.

  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash 
*flash, u32 offset,
                 if (ret)
                         break;

+               ret = spi_flash_cmd_write_disable(flash);
+               if (ret < 0) {
+                       printf("SF: disabling write failed\n");
+                       break;
+               }
+


Have anyone seen the above mentioned issues regarding read/write/erase? 
OR is there any
configurations that I might be missing ?



From adrian.hunter at intel.com  Wed Jun 12 03:58:21 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 12 Jun 2013 10:58:21 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
Message-ID: <51B82A1D.30009@intel.com>

This shows that the orphan area has recorded the orphaning of inode 0 (non-existent!) and inode 1 (root inode!!!).

A sticking plaster solution is to prevent orphans-processing from deleting the root inode e.g.

diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index ba32da3..9400b5b 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -613,6 +613,11 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
                for (i = 0; i < n; i++) {
                        inum = le64_to_cpu(orph->inos[i]);
+                       if (inum < UBIFS_FIRST_INO) {
+                               ubifs_err("*not* deleting orphaned inode %lu",
+                                         (unsigned long)inum);
+                               continue;
+                       }
                        dbg_rcvry("deleting orphaned inode %lu",
                                  (unsigned long)inum);
                        err = ubifs_tnc_remove_ino(c, inum);


On 11/06/13 15:16, Prins Anton (ST-CO/ENG1.1) wrote:
> Hi Artem,
> 
> We got logging inside the recovery procedure to print the 'orphan LEB' information.
> I wonder if the LEB9 moves yes/no? So is it safe to use 'dd' with an offset of 9*LEB?
> (Difficulty is we have no file system, so this was the first option...)
> 
> You see flood of message's; but I suppose the first part is the information required!
> If not I have to make some solution to go for 'dd'.
> 
> Thanks in advance,
> 
> Anton
> 
> 
> 
> leb9dump-filtered.log
> 
> 
> UBIFS: parse sync
> UBIFS: recovery needed
> ubi_leb_read datafs 9
> 00000000: 31 18 10 06 1a c9 4a be 09 ca 5d 00 00 00 00 00 28 00 00 00 0b 00 00 00 60 05 00 00 00 00 00 80  1.....J...].....(.......`.......
> 00000020: ea 88 0c 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00000040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................


struct ubifs_ch {
	__le32 magic;		06101831	06101831
	__le32 crc;		be4ac91a	ed207c74
	__le64 sqnum;		5dca09		0
	__le32 len;		28		1c
	__u8 node_type;		b=orph		5=pad
	__u8 group_type;	0		0
	__u8 padding[2];	0		0
} __packed;

struct ubifs_orph_node {
	struct ubifs_ch ch;
	__le64 cmt_no;		60 05 00 00 00 00 00 80
	__le64 inos[];		0c88ea
				
} __packed;

struct ubifs_pad_node {
	struct ubifs_ch ch;
	__le32 pad_len;		0fbc
} __packed;


<snip>

> 00001000: 31 18 10 06 33 f1 d9 f4 0c 80 6e 00 00 00 00 00 28 00 00 00 0b 00 00 00 73 05 00 00 00 00 00 80  1...3.....n.....(.......s.......
> 00001020: 9f ea 0e 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00001040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00001060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		73 05 00 00 00 00 00 80
	__le64 inos[];		0eea9f

<snip>

> 00002000: 31 18 10 06 c0 79 a0 c5 35 65 6f 00 00 00 00 00 28 00 00 00 0b 00 00 00 74 05 00 00 00 00 00 80  1....y..5eo.....(.......t.......
> 00002020: 4c 0b 0f 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  L.......1...t| .................
> 00002040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00002060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		74 05 00 00 00 00 00 80
	__le64 inos[];		0f0b4c

<snip>

> 00003000: 31 18 10 06 f8 40 ed 34 89 2f 71 00 00 00 00 00 28 00 00 00 0b 00 00 00 76 05 00 00 00 00 00 80  1.... at .4./q.....(.......v.......
> 00003020: 00 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00003040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00003060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		76 05 00 00 00 00 00 80
	__le64 inos[];		0				<----- !!!!!

<snip>

> 00004000: 31 18 10 06 43 37 1d 7e 00 73 77 00 00 00 00 00 28 00 00 00 0b 00 00 00 7d 05 00 00 00 00 00 80  1...C7.~.sw.....(.......}.......
> 00004020: 01 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00004040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00004060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		7d 05 00 00 00 00 00 80
	__le64 inos[];		1				<----- !!!!!

<snip>

> 00005000: 31 18 10 06 86 67 56 c0 53 c8 7d 00 00 00 00 00 28 00 00 00 0b 00 00 00 84 05 00 00 00 00 00 80  1....gV.S.}.....(...............
> 00005020: 8a 18 11 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00005040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00005060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		84 05 00 00 00 00 00 80
	__le64 inos[];		11188a

<snip>

> 00006000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................................

<snip>

> UBIFS: recovery completed
> UBIFS: mounted UBI device 1, volume 1, name "datafs"
> UBIFS: file system size:   640475136 bytes (625464 KiB, 610 MiB, 1241 LEBs)
> UBIFS: journal size:       10452992 bytes (10208 KiB, 9 MiB, 21 LEBs)
> UBIFS: media format:       w4/r0 (latest is w4/r0)
> UBIFS: default compressor: lzo
> UBIFS: reserved for root:  0 bytes (0 KiB)
> UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
> ubifs_fill_super couldn't read UBIFS_ROOT_INO
> 



From Anton.Prins at nl.bosch.com  Wed Jun 12 04:28:22 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Wed, 12 Jun 2013 10:28:22 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51B82A1D.30009@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A338D@SI-MBX14.de.bosch.com>

Thanks for the analysis,

I did do exactly the same before, but the plaster didn?t help. Here the log result; it still fails on the root node :(
Actually the root cause happens on a previous run/life-time; The question is how to get log information on this moment.
(More because we don't know how to reproduce except have many systems on for longer time)

<7>UBIFS DBG (pid 767): ubifs_bg_thread: background thread "ubifs_bgt1_1" started, PID 767
<5>UBIFS: recovery needed
<3>LEB 9
<3>deleting orphaned inode 821482
<3>last orph node for commit 1376 at 9:0
<3>deleting orphaned inode 977567
<3>last orph node for commit 1395 at 9:4096
<3>deleting orphaned inode 985932
<3>last orph node for commit 1396 at 9:8192
<3>prevent deleting orphaned inode 0
<5>UBIFS: recovery completed
<5>UBIFS: mounted UBI device 1, volume 1, name "datafs"
<5>UBIFS: file system size:   640475136 bytes (625464 KiB, 610 MiB, 1241 LEBs)
<5>UBIFS: journal size:       10452992 bytes (10208 KiB, 9 MiB, 21 LEBs)
<5>UBIFS: media format:       w4/r0 (latest is w4/r0)
<5>UBIFS: default compressor: lzo
<5>UBIFS: reserved for root:  0 bytes (0 KiB)
<7>UBIFS DBG (pid 1): mount_ubifs: compiled on:         May 31 2013 at 14:58:10
<7>UBIFS DBG (pid 1): mount_ubifs: min. I/O unit size:  4096 bytes
<7>UBIFS DBG (pid 1): mount_ubifs: max. write size:     4096 bytes
<7>UBIFS DBG (pid 1): mount_ubifs: LEB size:            516096 bytes (504 KiB)
<7>UBIFS DBG (pid 1): mount_ubifs: data journal heads:  1
<7>UBIFS DBG (pid 1): mount_ubifs: UUID:                1D1AD726-53AB-4623-8D86-B7773B5EFA83
<7>UBIFS DBG (pid 1): mount_ubifs: big_lpt              0
<7>UBIFS DBG (pid 1): mount_ubifs: log LEBs:            4 (3 - 6)
<7>UBIFS DBG (pid 1): mount_ubifs: LPT area LEBs:       2 (7 - 8)
<7>UBIFS DBG (pid 1): mount_ubifs: orphan area LEBs:    1 (9 - 9)
<7>UBIFS DBG (pid 1): mount_ubifs: main area LEBs:      1241 (10 - 1250)
<7>UBIFS DBG (pid 1): mount_ubifs: index LEBs:          31
<7>UBIFS DBG (pid 1): mount_ubifs: total index bytes:   702944 (686 KiB, 0 MiB)
<7>UBIFS DBG (pid 1): mount_ubifs: key hash type:       0
<7>UBIFS DBG (pid 1): mount_ubifs: tree fanout:         8
<7>UBIFS DBG (pid 1): mount_ubifs: reserved GC LEB:     166
<7>UBIFS DBG (pid 1): mount_ubifs: first main LEB:      10
<7>UBIFS DBG (pid 1): mount_ubifs: max. znode size      240
<7>UBIFS DBG (pid 1): mount_ubifs: max. index node size 192
<7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          data 48, inode 160, dentry 56
<7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          trun 56, sb 4096, master 512
<7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          ref 64, cmt. start 32, orph 32
<7>UBIFS DBG (pid 1): mount_ubifs: max. node sizes:     data 4144, inode 4256 dentry 312, idx 188
<7>UBIFS DBG (pid 1): mount_ubifs: dead watermark:      4096
<7>UBIFS DBG (pid 1): mount_ubifs: dark watermark:      8192
<7>UBIFS DBG (pid 1): mount_ubifs: LEB overhead:        2240
<7>UBIFS DBG (pid 1): mount_ubifs: max. dark space:     10166272 (9928 KiB, 9 MiB)
<7>UBIFS DBG (pid 1): mount_ubifs: maximum bud bytes:   8388608 (8192 KiB, 8 MiB)
<7>UBIFS DBG (pid 1): mount_ubifs: BG commit bud bytes: 6815744 (6656 KiB, 6 MiB)
<7>UBIFS DBG (pid 1): mount_ubifs: current bud bytes    405504 (396 KiB, 0 MiB)
<7>UBIFS DBG (pid 1): mount_ubifs: max. seq. number:    8296008
<7>UBIFS DBG (pid 1): mount_ubifs: commit number:       1461
<3>UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
<7>UBIFS DBG (pid 767): ubifs_bg_thread: background thread "ubifs_bgt1_1" stops

Met vriendelijke groeten | Best Regards, 
Anton Prins

-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: woensdag 12 juni 2013 9:58
To: Prins Anton (ST-CO/ENG1.1)
Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
Subject: Re: UBIFS failure & stable page writes

This shows that the orphan area has recorded the orphaning of inode 0 (non-existent!) and inode 1 (root inode!!!).

A sticking plaster solution is to prevent orphans-processing from deleting the root inode e.g.

diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index ba32da3..9400b5b 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -613,6 +613,11 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
                for (i = 0; i < n; i++) {
                        inum = le64_to_cpu(orph->inos[i]);
+                       if (inum < UBIFS_FIRST_INO) {
+                               ubifs_err("*not* deleting orphaned inode %lu",
+                                         (unsigned long)inum);
+                               continue;
+                       }
                        dbg_rcvry("deleting orphaned inode %lu",
                                  (unsigned long)inum);
                        err = ubifs_tnc_remove_ino(c, inum);


On 11/06/13 15:16, Prins Anton (ST-CO/ENG1.1) wrote:
> Hi Artem,
> 
> We got logging inside the recovery procedure to print the 'orphan LEB' information.
> I wonder if the LEB9 moves yes/no? So is it safe to use 'dd' with an offset of 9*LEB?
> (Difficulty is we have no file system, so this was the first option...)
> 
> You see flood of message's; but I suppose the first part is the information required!
> If not I have to make some solution to go for 'dd'.
> 
> Thanks in advance,
> 
> Anton
> 
> 
> 
> leb9dump-filtered.log
> 
> 
> UBIFS: parse sync
> UBIFS: recovery needed
> ubi_leb_read datafs 9
> 00000000: 31 18 10 06 1a c9 4a be 09 ca 5d 00 00 00 00 00 28 00 00 00 0b 00 00 00 60 05 00 00 00 00 00 80  1.....J...].....(.......`.......
> 00000020: ea 88 0c 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00000040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................


struct ubifs_ch {
	__le32 magic;		06101831	06101831
	__le32 crc;		be4ac91a	ed207c74
	__le64 sqnum;		5dca09		0
	__le32 len;		28		1c
	__u8 node_type;		b=orph		5=pad
	__u8 group_type;	0		0
	__u8 padding[2];	0		0
} __packed;

struct ubifs_orph_node {
	struct ubifs_ch ch;
	__le64 cmt_no;		60 05 00 00 00 00 00 80
	__le64 inos[];		0c88ea
				
} __packed;

struct ubifs_pad_node {
	struct ubifs_ch ch;
	__le32 pad_len;		0fbc
} __packed;


<snip>

> 00001000: 31 18 10 06 33 f1 d9 f4 0c 80 6e 00 00 00 00 00 28 00 00 00 0b 00 00 00 73 05 00 00 00 00 00 80  1...3.....n.....(.......s.......
> 00001020: 9f ea 0e 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00001040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00001060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		73 05 00 00 00 00 00 80
	__le64 inos[];		0eea9f

<snip>

> 00002000: 31 18 10 06 c0 79 a0 c5 35 65 6f 00 00 00 00 00 28 00 00 00 0b 00 00 00 74 05 00 00 00 00 00 80  1....y..5eo.....(.......t.......
> 00002020: 4c 0b 0f 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  L.......1...t| .................
> 00002040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00002060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		74 05 00 00 00 00 00 80
	__le64 inos[];		0f0b4c

<snip>

> 00003000: 31 18 10 06 f8 40 ed 34 89 2f 71 00 00 00 00 00 28 00 00 00 0b 00 00 00 76 05 00 00 00 00 00 80  1.... at .4./q.....(.......v.......
> 00003020: 00 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00003040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00003060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		76 05 00 00 00 00 00 80
	__le64 inos[];		0				<----- !!!!!

<snip>

> 00004000: 31 18 10 06 43 37 1d 7e 00 73 77 00 00 00 00 00 28 00 00 00 0b 00 00 00 7d 05 00 00 00 00 00 80  1...C7.~.sw.....(.......}.......
> 00004020: 01 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00004040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00004060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		7d 05 00 00 00 00 00 80
	__le64 inos[];		1				<----- !!!!!

<snip>

> 00005000: 31 18 10 06 86 67 56 c0 53 c8 7d 00 00 00 00 00 28 00 00 00 0b 00 00 00 84 05 00 00 00 00 00 80  1....gV.S.}.....(...............
> 00005020: 8a 18 11 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
> 00005040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 00005060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................

	__le32 len;		28
	__le64 cmt_no;		84 05 00 00 00 00 00 80
	__le64 inos[];		11188a

<snip>

> 00006000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................................

<snip>

> UBIFS: recovery completed
> UBIFS: mounted UBI device 1, volume 1, name "datafs"
> UBIFS: file system size:   640475136 bytes (625464 KiB, 610 MiB, 1241 LEBs)
> UBIFS: journal size:       10452992 bytes (10208 KiB, 9 MiB, 21 LEBs)
> UBIFS: media format:       w4/r0 (latest is w4/r0)
> UBIFS: default compressor: lzo
> UBIFS: reserved for root:  0 bytes (0 KiB)
> UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
> ubifs_fill_super couldn't read UBIFS_ROOT_INO
> 


From pekon at ti.com  Wed Jun 12 06:25:05 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 15:55:05 +0530
Subject: [v4 0/3] suspend/resume support for OMAP nand driver
Message-ID: <1371032708-9242-1-git-send-email-pekon@ti.com>

This patch series adds low power transition support for OMAP NAND driver.
[Patch 1/3]: Adds pm_runtime calls to handle GPMC module probe and remove
[Patch 2/3]: Adds GPMC suspend/resume support.
[Patch 3/3]: Adds ELM suspend/resume support.

Tested on am335x-evm with NAND flash support, using following:
	echo devices 	> /sys/power/pm_test
	echo mem	> /sys/power/state

	echo core	> /sys/power/pm_test
	echo mem	> /sys/power/state

Changes Since v3:
- CONFIG_PM -> CONFIG_PM_SLEEP
- using struct dev_pm_ops via driver->pm, instead of struct platform_driver
- rebased to 3.10-rc5

Changes Since v2:
- Remove calll back of nand_suspend from omap2 nand driver, as the same call
  already done from suspend activity mtd class driver.

[1] http://comments.gmane.org/gmane.linux.ports.arm.omap/91405


avinash philip (3):
  arm: gpmc: Converts GPMC driver to pm_runtime capable
  arm: gpmc: Low power transition support
  mtd: devices: elm: Low power transition support

 arch/arm/mach-omap2/gpmc.c | 27 +++++++++++++++++++++++++--
 drivers/mtd/devices/elm.c  | 19 +++++++++++++++++++
 2 files changed, 44 insertions(+), 2 deletions(-)

-- 
1.8.1



From pekon at ti.com  Wed Jun 12 06:50:35 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:20:35 +0530
Subject: [PATCH v4 3/3] mtd: devices: elm: Low power transition support
In-Reply-To: <1371034235-18720-1-git-send-email-pekon@ti.com>
References: <1371034235-18720-1-git-send-email-pekon@ti.com>
Message-ID: <1371034235-18720-3-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

In low power modes of AM335X platforms, peripherals power is cut off.
This patch supports low power sleep transition support for ELM driver.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 drivers/mtd/devices/elm.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
index dccef9f..171efcd 100644
--- a/drivers/mtd/devices/elm.c
+++ b/drivers/mtd/devices/elm.c
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 
@@ -385,6 +386,23 @@ static int elm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int elm_suspend(struct device *dev)
+{
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+
+	pm_runtime_get_sync(dev);
+	elm_config(dev, info->bch_type);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
 	{ .compatible = "ti,am3352-elm" },
@@ -398,6 +416,7 @@ static struct platform_driver elm_driver = {
 		.name	= "elm",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(elm_of_match),
+		.pm	= &elm_pm_ops,
 	},
 	.probe	= elm_probe,
 	.remove	= elm_remove,
-- 
1.8.1



From pekon at ti.com  Wed Jun 12 06:50:34 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:20:34 +0530
Subject: [PATCH v4 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371034235-18720-1-git-send-email-pekon@ti.com>
References: <1371034235-18720-1-git-send-email-pekon@ti.com>
Message-ID: <1371034235-18720-2-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

With GPMC converted to platform driver recently, adds low power
transition support in driver itself.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1380cee..b5c4752 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1655,6 +1655,24 @@ static int gpmc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpmc_suspend(struct device *dev)
+{
+	omap3_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap3_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
 static struct platform_driver gpmc_driver = {
 	.probe		= gpmc_probe,
 	.remove		= gpmc_remove,
@@ -1662,6 +1680,7 @@ static struct platform_driver gpmc_driver = {
 		.name	= DEVICE_NAME,
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
 	},
 };
 
-- 
1.8.1



From pekon at ti.com  Wed Jun 12 06:50:33 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:20:33 +0530
Subject: [PATCH v4 1/3] arm: gpmc: Converts GPMC driver to pm_runtime capable
Message-ID: <1371034235-18720-1-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

Support for pm_runtime add to GPMC driver.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com> 
---
 arch/arm/mach-omap2/gpmc.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index fb6f241..1380cee 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/mtd/nand.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -1594,7 +1595,8 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_l3_clk);
 	}
 
-	clk_prepare_enable(gpmc_l3_clk);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	gpmc_dev = &pdev->dev;
 
@@ -1634,7 +1636,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	rc = gpmc_probe_dt(pdev);
 	if (rc < 0) {
-		clk_disable_unprepare(gpmc_l3_clk);
+		pm_runtime_put_sync(&pdev->dev);
 		clk_put(gpmc_l3_clk);
 		dev_err(gpmc_dev, "failed to probe DT parameters\n");
 		return rc;
@@ -1647,6 +1649,8 @@ static int gpmc_remove(struct platform_device *pdev)
 {
 	gpmc_free_irq();
 	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	gpmc_dev = NULL;
 	return 0;
 }
-- 
1.8.1



From pekon at ti.com  Wed Jun 12 07:00:57 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:30:57 +0530
Subject: [PATCH v4 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371034858-19984-1-git-send-email-pekon@ti.com>
References: <1371034858-19984-1-git-send-email-pekon@ti.com>
Message-ID: <1371034858-19984-3-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

With GPMC converted to platform driver recently, adds low power
transition support in driver itself.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1380cee..b5c4752 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1655,6 +1655,24 @@ static int gpmc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpmc_suspend(struct device *dev)
+{
+	omap3_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap3_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
 static struct platform_driver gpmc_driver = {
 	.probe		= gpmc_probe,
 	.remove		= gpmc_remove,
@@ -1662,6 +1680,7 @@ static struct platform_driver gpmc_driver = {
 		.name	= DEVICE_NAME,
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
 	},
 };
 
-- 
1.8.1



From pekon at ti.com  Wed Jun 12 07:00:56 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:30:56 +0530
Subject: [PATCH v4 1/3] arm: gpmc: Converts GPMC driver to pm_runtime capable
In-Reply-To: <1371034858-19984-1-git-send-email-pekon@ti.com>
References: <1371034858-19984-1-git-send-email-pekon@ti.com>
Message-ID: <1371034858-19984-2-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

Support for pm_runtime add to GPMC driver.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com> 
---
 arch/arm/mach-omap2/gpmc.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index fb6f241..1380cee 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/mtd/nand.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -1594,7 +1595,8 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_l3_clk);
 	}
 
-	clk_prepare_enable(gpmc_l3_clk);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	gpmc_dev = &pdev->dev;
 
@@ -1634,7 +1636,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	rc = gpmc_probe_dt(pdev);
 	if (rc < 0) {
-		clk_disable_unprepare(gpmc_l3_clk);
+		pm_runtime_put_sync(&pdev->dev);
 		clk_put(gpmc_l3_clk);
 		dev_err(gpmc_dev, "failed to probe DT parameters\n");
 		return rc;
@@ -1647,6 +1649,8 @@ static int gpmc_remove(struct platform_device *pdev)
 {
 	gpmc_free_irq();
 	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	gpmc_dev = NULL;
 	return 0;
 }
-- 
1.8.1



From pekon at ti.com  Wed Jun 12 07:00:55 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:30:55 +0530
Subject: [PATCH v4 0/3] suspend/resume support for OMAP nand driver
Message-ID: <1371034858-19984-1-git-send-email-pekon@ti.com>

This patch series adds low power transition support for OMAP NAND driver.
[Patch 1/3]: Adds pm_runtime calls to handle GPMC module probe and remove
[Patch 2/3]: Adds GPMC suspend/resume support.
[Patch 3/3]: Adds ELM suspend/resume support.

Tested on am335x-evm with NAND flash support, using following:
	echo devices 	> /sys/power/pm_test
	echo mem	> /sys/power/state

	echo core	> /sys/power/pm_test
	echo mem	> /sys/power/state

Changes Since v3:
- CONFIG_PM -> CONFIG_PM_SLEEP
- using struct dev_pm_ops via driver->pm, instead of struct platform_driver
- rebased to 3.10-rc5

Changes Since v2:
- Remove calll back of nand_suspend from omap2 nand driver, as the same call
  already done from suspend activity mtd class driver.

[1] http://comments.gmane.org/gmane.linux.ports.arm.omap/91405


avinash philip (3):
  arm: gpmc: Converts GPMC driver to pm_runtime capable
  arm: gpmc: Low power transition support
  mtd: devices: elm: Low power transition support

 arch/arm/mach-omap2/gpmc.c | 27 +++++++++++++++++++++++++--
 drivers/mtd/devices/elm.c  | 19 +++++++++++++++++++
 2 files changed, 44 insertions(+), 2 deletions(-)

-- 
1.8.1



From pekon at ti.com  Wed Jun 12 07:00:58 2013
From: pekon at ti.com (Pekon Gupta)
Date: Wed, 12 Jun 2013 16:30:58 +0530
Subject: [PATCH v4 3/3] mtd: devices: elm: Low power transition support
In-Reply-To: <1371034858-19984-1-git-send-email-pekon@ti.com>
References: <1371034858-19984-1-git-send-email-pekon@ti.com>
Message-ID: <1371034858-19984-4-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

In low power modes of AM335X platforms, peripherals power is cut off.
This patch supports low power sleep transition support for ELM driver.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 drivers/mtd/devices/elm.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
index dccef9f..171efcd 100644
--- a/drivers/mtd/devices/elm.c
+++ b/drivers/mtd/devices/elm.c
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 
@@ -385,6 +386,23 @@ static int elm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int elm_suspend(struct device *dev)
+{
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+
+	pm_runtime_get_sync(dev);
+	elm_config(dev, info->bch_type);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
 	{ .compatible = "ti,am3352-elm" },
@@ -398,6 +416,7 @@ static struct platform_driver elm_driver = {
 		.name	= "elm",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(elm_of_match),
+		.pm	= &elm_pm_ops,
 	},
 	.probe	= elm_probe,
 	.remove	= elm_remove,
-- 
1.8.1



From Anton.Prins at nl.bosch.com  Wed Jun 12 07:13:06 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Wed, 12 Jun 2013 13:13:06 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51B82A1D.30009@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>

Does it make sense to use chk_orphans?

I suppose I have to do: $ echo "1" > chk_orphans

Or am I wrong?

Met vriendelijke groeten | Best Regards, 
Anton Prins


From adrian.hunter at intel.com  Wed Jun 12 07:40:31 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 12 Jun 2013 14:40:31 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A338D@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A338D@SI-MBX14.de.bosch.com>
Message-ID: <51B85E2F.7040009@intel.com>

On 12/06/13 11:28, Prins Anton (ST-CO/ENG1.1) wrote:
> Thanks for the analysis,
>
> I did do exactly the same before, but the plaster didn?t help. Here the log result; it still fails on the root node :(

It seems the root inode was not deleted by orphans in this case.  You need
to enable mount messages to see if it was deleted by the recovery.
On older version of UBIFS you can do that by setting debug_msgs to 4

> Actually the root cause happens on a previous run/life-time; The question is how to get log information on this moment.
> (More because we don't know how to reproduce except have many systems on for longer time)
>
> <7>UBIFS DBG (pid 767): ubifs_bg_thread: background thread "ubifs_bgt1_1" started, PID 767
> <5>UBIFS: recovery needed
> <3>LEB 9
> <3>deleting orphaned inode 821482
> <3>last orph node for commit 1376 at 9:0
> <3>deleting orphaned inode 977567
> <3>last orph node for commit 1395 at 9:4096
> <3>deleting orphaned inode 985932
> <3>last orph node for commit 1396 at 9:8192
> <3>prevent deleting orphaned inode 0
> <5>UBIFS: recovery completed
> <5>UBIFS: mounted UBI device 1, volume 1, name "datafs"
> <5>UBIFS: file system size:   640475136 bytes (625464 KiB, 610 MiB, 1241 LEBs)
> <5>UBIFS: journal size:       10452992 bytes (10208 KiB, 9 MiB, 21 LEBs)
> <5>UBIFS: media format:       w4/r0 (latest is w4/r0)
> <5>UBIFS: default compressor: lzo
> <5>UBIFS: reserved for root:  0 bytes (0 KiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: compiled on:         May 31 2013 at 14:58:10
> <7>UBIFS DBG (pid 1): mount_ubifs: min. I/O unit size:  4096 bytes
> <7>UBIFS DBG (pid 1): mount_ubifs: max. write size:     4096 bytes
> <7>UBIFS DBG (pid 1): mount_ubifs: LEB size:            516096 bytes (504 KiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: data journal heads:  1
> <7>UBIFS DBG (pid 1): mount_ubifs: UUID:                1D1AD726-53AB-4623-8D86-B7773B5EFA83
> <7>UBIFS DBG (pid 1): mount_ubifs: big_lpt              0
> <7>UBIFS DBG (pid 1): mount_ubifs: log LEBs:            4 (3 - 6)
> <7>UBIFS DBG (pid 1): mount_ubifs: LPT area LEBs:       2 (7 - 8)
> <7>UBIFS DBG (pid 1): mount_ubifs: orphan area LEBs:    1 (9 - 9)
> <7>UBIFS DBG (pid 1): mount_ubifs: main area LEBs:      1241 (10 - 1250)
> <7>UBIFS DBG (pid 1): mount_ubifs: index LEBs:          31
> <7>UBIFS DBG (pid 1): mount_ubifs: total index bytes:   702944 (686 KiB, 0 MiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: key hash type:       0
> <7>UBIFS DBG (pid 1): mount_ubifs: tree fanout:         8
> <7>UBIFS DBG (pid 1): mount_ubifs: reserved GC LEB:     166
> <7>UBIFS DBG (pid 1): mount_ubifs: first main LEB:      10
> <7>UBIFS DBG (pid 1): mount_ubifs: max. znode size      240
> <7>UBIFS DBG (pid 1): mount_ubifs: max. index node size 192
> <7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          data 48, inode 160, dentry 56
> <7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          trun 56, sb 4096, master 512
> <7>UBIFS DBG (pid 1): mount_ubifs: node sizes:          ref 64, cmt. start 32, orph 32
> <7>UBIFS DBG (pid 1): mount_ubifs: max. node sizes:     data 4144, inode 4256 dentry 312, idx 188
> <7>UBIFS DBG (pid 1): mount_ubifs: dead watermark:      4096
> <7>UBIFS DBG (pid 1): mount_ubifs: dark watermark:      8192
> <7>UBIFS DBG (pid 1): mount_ubifs: LEB overhead:        2240
> <7>UBIFS DBG (pid 1): mount_ubifs: max. dark space:     10166272 (9928 KiB, 9 MiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: maximum bud bytes:   8388608 (8192 KiB, 8 MiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: BG commit bud bytes: 6815744 (6656 KiB, 6 MiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: current bud bytes    405504 (396 KiB, 0 MiB)
> <7>UBIFS DBG (pid 1): mount_ubifs: max. seq. number:    8296008
> <7>UBIFS DBG (pid 1): mount_ubifs: commit number:       1461
> <3>UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
> <7>UBIFS DBG (pid 767): ubifs_bg_thread: background thread "ubifs_bgt1_1" stops
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
> Sent: woensdag 12 juni 2013 9:58
> To: Prins Anton (ST-CO/ENG1.1)
> Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
> Subject: Re: UBIFS failure & stable page writes
>
> This shows that the orphan area has recorded the orphaning of inode 0 (non-existent!) and inode 1 (root inode!!!).
>
> A sticking plaster solution is to prevent orphans-processing from deleting the root inode e.g.
>
> diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
> index ba32da3..9400b5b 100644
> --- a/fs/ubifs/orphan.c
> +++ b/fs/ubifs/orphan.c
> @@ -613,6 +613,11 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
>                 n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
>                 for (i = 0; i < n; i++) {
>                         inum = le64_to_cpu(orph->inos[i]);
> +                       if (inum < UBIFS_FIRST_INO) {
> +                               ubifs_err("*not* deleting orphaned inode %lu",
> +                                         (unsigned long)inum);
> +                               continue;
> +                       }
>                         dbg_rcvry("deleting orphaned inode %lu",
>                                   (unsigned long)inum);
>                         err = ubifs_tnc_remove_ino(c, inum);
>
>
> On 11/06/13 15:16, Prins Anton (ST-CO/ENG1.1) wrote:
>> Hi Artem,
>>
>> We got logging inside the recovery procedure to print the 'orphan LEB' information.
>> I wonder if the LEB9 moves yes/no? So is it safe to use 'dd' with an offset of 9*LEB?
>> (Difficulty is we have no file system, so this was the first option...)
>>
>> You see flood of message's; but I suppose the first part is the information required!
>> If not I have to make some solution to go for 'dd'.
>>
>> Thanks in advance,
>>
>> Anton
>>
>>
>>
>> leb9dump-filtered.log
>>
>>
>> UBIFS: parse sync
>> UBIFS: recovery needed
>> ubi_leb_read datafs 9
>> 00000000: 31 18 10 06 1a c9 4a be 09 ca 5d 00 00 00 00 00 28 00 00 00 0b 00 00 00 60 05 00 00 00 00 00 80  1.....J...].....(.......`.......
>> 00000020: ea 88 0c 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
>> 00000040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>
> struct ubifs_ch {
> 	__le32 magic;		06101831	06101831
> 	__le32 crc;		be4ac91a	ed207c74
> 	__le64 sqnum;		5dca09		0
> 	__le32 len;		28		1c
> 	__u8 node_type;		b=orph		5=pad
> 	__u8 group_type;	0		0
> 	__u8 padding[2];	0		0
> } __packed;
>
> struct ubifs_orph_node {
> 	struct ubifs_ch ch;
> 	__le64 cmt_no;		60 05 00 00 00 00 00 80
> 	__le64 inos[];		0c88ea
> 				
> } __packed;
>
> struct ubifs_pad_node {
> 	struct ubifs_ch ch;
> 	__le32 pad_len;		0fbc
> } __packed;
>
>
> <snip>
>
>> 00001000: 31 18 10 06 33 f1 d9 f4 0c 80 6e 00 00 00 00 00 28 00 00 00 0b 00 00 00 73 05 00 00 00 00 00 80  1...3.....n.....(.......s.......
>> 00001020: 9f ea 0e 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
>> 00001040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00001060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 	__le32 len;		28
> 	__le64 cmt_no;		73 05 00 00 00 00 00 80
> 	__le64 inos[];		0eea9f
>
> <snip>
>
>> 00002000: 31 18 10 06 c0 79 a0 c5 35 65 6f 00 00 00 00 00 28 00 00 00 0b 00 00 00 74 05 00 00 00 00 00 80  1....y..5eo.....(.......t.......
>> 00002020: 4c 0b 0f 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  L.......1...t| .................
>> 00002040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00002060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 	__le32 len;		28
> 	__le64 cmt_no;		74 05 00 00 00 00 00 80
> 	__le64 inos[];		0f0b4c
>
> <snip>
>
>> 00003000: 31 18 10 06 f8 40 ed 34 89 2f 71 00 00 00 00 00 28 00 00 00 0b 00 00 00 76 05 00 00 00 00 00 80  1.... at .4./q.....(.......v.......
>> 00003020: 00 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
>> 00003040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00003060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 	__le32 len;		28
> 	__le64 cmt_no;		76 05 00 00 00 00 00 80
> 	__le64 inos[];		0				<----- !!!!!
>
> <snip>
>
>> 00004000: 31 18 10 06 43 37 1d 7e 00 73 77 00 00 00 00 00 28 00 00 00 0b 00 00 00 7d 05 00 00 00 00 00 80  1...C7.~.sw.....(.......}.......
>> 00004020: 01 00 00 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
>> 00004040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00004060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 	__le32 len;		28
> 	__le64 cmt_no;		7d 05 00 00 00 00 00 80
> 	__le64 inos[];		1				<----- !!!!!
>
> <snip>
>
>> 00005000: 31 18 10 06 86 67 56 c0 53 c8 7d 00 00 00 00 00 28 00 00 00 0b 00 00 00 84 05 00 00 00 00 00 80  1....gV.S.}.....(...............
>> 00005020: 8a 18 11 00 00 00 00 00 31 18 10 06 74 7c 20 ed 00 00 00 00 00 00 00 00 1c 00 00 00 05 00 00 00  ........1...t| .................
>> 00005040: bc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
>> 00005060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
> 	__le32 len;		28
> 	__le64 cmt_no;		84 05 00 00 00 00 00 80
> 	__le64 inos[];		11188a
>
> <snip>
>
>> 00006000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................................
> <snip>
>
>> UBIFS: recovery completed
>> UBIFS: mounted UBI device 1, volume 1, name "datafs"
>> UBIFS: file system size:   640475136 bytes (625464 KiB, 610 MiB, 1241 LEBs)
>> UBIFS: journal size:       10452992 bytes (10208 KiB, 9 MiB, 21 LEBs)
>> UBIFS: media format:       w4/r0 (latest is w4/r0)
>> UBIFS: default compressor: lzo
>> UBIFS: reserved for root:  0 bytes (0 KiB)
>> UBIFS error (pid 1): ubifs_iget: failed to read inode 1, error -2
>> ubifs_fill_super couldn't read UBIFS_ROOT_INO
>>



From adrian.hunter at intel.com  Wed Jun 12 08:00:22 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 12 Jun 2013 15:00:22 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
Message-ID: <51B862D6.2080807@intel.com>

On 12/06/13 14:13, Prins Anton (ST-CO/ENG1.1) wrote:
> Does it make sense to use chk_orphans?

That checks for missing orphans but the problem is the opposite: the
presence of orphans that should not be there.

>
> I suppose I have to do: $ echo "1" > chk_orphans
>
> Or am I wrong?
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>



From Anton.Prins at nl.bosch.com  Wed Jun 12 07:57:54 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Wed, 12 Jun 2013 13:57:54 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51B862D6.2080807@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>

Ok clear!

Regarding mount debug: I suppose I only will see this on the 'first' boot after the problem is in the persistence storage?
(Up to now I'm not able to signal the point-of-failure... I'm only looking to an (possibly) after recovery situation).

Or makes this sense to do this mount debug on the existing failing device?

FYI: 
- with 100 devices power cycling every 5 minutes for a weekend we DON'T see a problem.
- with 100 devices powered on for a weekend and after that give a single power-cycle shows maybe 1 or 2 failing devices (but sometimes '0').

So a main problem in analyzing is the 'moment of failure' and 'reproduction (rate)'.

Met vriendelijke groeten | Best Regards, 
Anton Prins

Met vriendelijke groeten | Best Regards, 
Anton Prins


-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: woensdag 12 juni 2013 14:00
To: Prins Anton (ST-CO/ENG1.1)
Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
Subject: Re: UBIFS failure & stable page writes

On 12/06/13 14:13, Prins Anton (ST-CO/ENG1.1) wrote:
> Does it make sense to use chk_orphans?

That checks for missing orphans but the problem is the opposite: the
presence of orphans that should not be there.

>
> I suppose I have to do: $ echo "1" > chk_orphans
>
> Or am I wrong?
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>


From plagnioj at jcrosoft.com  Wed Jun 12 07:57:48 2013
From: plagnioj at jcrosoft.com (Jean-Christophe PLAGNIOL-VILLARD)
Date: Wed, 12 Jun 2013 13:57:48 +0200
Subject: [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with
 one function.
In-Reply-To: <1370860014-1770-3-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-3-git-send-email-josh.wu@atmel.com>
Message-ID: <20130612115748.GQ23653@game.jcrosoft.org>

On 18:26 Mon 10 Jun     , Josh Wu wrote:
> Signed-off-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>

Best Regards,
J.
> ---
>  drivers/mtd/nand/atmel_nand.c |   40 +++++++++++++++++++++++++---------------
>  1 file changed, 25 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index c7a4016..7236415 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -754,6 +754,29 @@ normal_check:
>  	return total_err;
>  }
>  
> +static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
> +{
> +	u32 val;
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> +	val = pmecc_readl_relaxed(host->ecc, CFG);
> +
> +	if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
> +		dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
> +		return;
> +	}
> +
> +	if (ecc_op == NAND_ECC_READ)
> +		pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
> +			| PMECC_CFG_AUTO_ENABLE);
> +	else
> +		pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
> +			& ~PMECC_CFG_AUTO_ENABLE);
> +
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
> +}
> +
>  static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
>  	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
>  {
> @@ -765,13 +788,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
>  	unsigned long end_time;
>  	int bitflips = 0;
>  
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> -	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
> -		& ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
> -
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
> +	pmecc_enable(host, NAND_ECC_READ);
>  
>  	chip->read_buf(mtd, buf, eccsize);
>  	chip->read_buf(mtd, oob, mtd->oobsize);
> @@ -804,14 +821,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
>  	int i, j;
>  	unsigned long end_time;
>  
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> -
> -	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
> -		PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
> -
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
> -	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
> +	pmecc_enable(host, NAND_ECC_WRITE);
>  
>  	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
>  
> -- 
> 1.7.9.5
> 


From plagnioj at jcrosoft.com  Wed Jun 12 07:58:03 2013
From: plagnioj at jcrosoft.com (Jean-Christophe PLAGNIOL-VILLARD)
Date: Wed, 12 Jun 2013 13:58:03 +0200
Subject: [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller
 (NFC) read data via sram
In-Reply-To: <1370860014-1770-5-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-5-git-send-email-josh.wu@atmel.com>
Message-ID: <20130612115803.GR23653@game.jcrosoft.org>

On 18:26 Mon 10 Jun     , Josh Wu wrote:
> NFC has embedded sram which can use to transfer data. This patch enable reading
> nand flash via NFC SRAM. It will minimize the CPU overhead.
> 
> This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
> mtd-utils.
> 
> Here puts the part of mtd_speedtest (read test) result as following:
> Compare with non-NFC mtd_speedtest result, reading will reduce %45 cpu load
> with increase %80 speed.
> 
> - commands use to test:
>   # insmod /mnt/mtd_speedtest.ko dev=2 &
>   # top -n 30 -d 1 | grep speedtest
> 
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>

Best Regards,
J.
> - test result:
> =================================================
> mtd_speedtest: MTD device: 2
> mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
> mtd_speedtest: testing eraseblock read speed
>   509   495 root     D     1164   0%  28% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  26% insmod /mnt/mtd_speedtest.ko dev=2
> mtd_speedtest: eraseblock read speed is 9403 KiB/s
> mtd_speedtest: testing page read speed
>   509   495 root     R     1164   0%  31% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  57% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  53% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  71% insmod /mnt/mtd_speedtest.ko dev=2
> mtd_speedtest: page read speed is 9258 KiB/s
> 
> Signed-off-by: Josh Wu <josh.wu at atmel.com>
> ---
> v2 --> v3:
>   - if NFC sram address and size is specified then enable NFC sram read.
>     Otherwise disable NFC sram read.
> 
>  drivers/mtd/nand/atmel_nand.c |  163 +++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 157 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index bf3370b..c2ec740 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -96,9 +96,13 @@ struct atmel_nfc {
>  	void __iomem		*hsmc_regs;
>  	void __iomem		*sram_bank0;
>  	dma_addr_t		sram_bank0_phys;
> +	bool			use_nfc_sram;
>  
>  	bool			is_initialized;
>  	struct completion	comp_nfc;
> +
> +	/* Point to the sram bank which include readed data via NFC */
> +	void __iomem		*data_in_sram;
>  };
>  static struct atmel_nfc	nand_nfc;
>  
> @@ -251,24 +255,47 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
>  			return res;
>  		}
>  	}
> +
>  	return res;
>  }
>  
> +static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
> +{
> +	int i;
> +	u32 *t = trg;
> +	const __iomem u32 *s = src;
> +
> +	for (i = 0; i < (size >> 2); i++)
> +		*t++ = readl_relaxed(s++);
> +}
> +
>  /*
>   * Minimal-overhead PIO for data access.
>   */
>  static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
>  {
>  	struct nand_chip	*nand_chip = mtd->priv;
> +	struct atmel_nand_host *host = nand_chip->priv;
>  
> -	__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
> +	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
> +		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
> +		host->nfc->data_in_sram += len;
> +	} else {
> +		__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
> +	}
>  }
>  
>  static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
>  {
>  	struct nand_chip	*nand_chip = mtd->priv;
> +	struct atmel_nand_host *host = nand_chip->priv;
>  
> -	__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
> +	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
> +		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
> +		host->nfc->data_in_sram += len;
> +	} else {
> +		__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
> +	}
>  }
>  
>  static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
> @@ -290,6 +317,40 @@ static void dma_complete_func(void *completion)
>  	complete(completion);
>  }
>  
> +static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
> +{
> +	/* NFC only has two banks. Must be 0 or 1 */
> +	if (bank > 1)
> +		return -EINVAL;
> +
> +	if (bank) {
> +		/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
> +		if (host->mtd.writesize > 2048)
> +			return -EINVAL;
> +		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
> +	} else {
> +		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
> +	}
> +
> +	return 0;
> +}
> +
> +static uint nfc_get_sram_off(struct atmel_nand_host *host)
> +{
> +	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
> +		return NFC_SRAM_BANK1_OFFSET;
> +	else
> +		return 0;
> +}
> +
> +static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
> +{
> +	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
> +		return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
> +	else
> +		return host->nfc->sram_bank0_phys;
> +}
> +
>  static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
>  			       int is_read)
>  {
> @@ -303,6 +364,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
>  	void *p = buf;
>  	int err = -EIO;
>  	enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> +	struct atmel_nfc *nfc = host->nfc;
>  
>  	if (buf >= high_memory)
>  		goto err_buf;
> @@ -319,7 +381,12 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
>  	}
>  
>  	if (is_read) {
> -		dma_src_addr = host->io_phys;
> +		if (nfc && nfc->data_in_sram)
> +			dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
> +				- (nfc->sram_bank0 + nfc_get_sram_off(host)));
> +		else
> +			dma_src_addr = host->io_phys;
> +
>  		dma_dst_addr = phys_addr;
>  	} else {
>  		dma_src_addr = phys_addr;
> @@ -346,6 +413,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
>  	dma_async_issue_pending(host->dma_chan);
>  	wait_for_completion(&host->comp);
>  
> +	if (is_read && nfc && nfc->data_in_sram)
> +		/* After read data from SRAM, need to increase the position */
> +		nfc->data_in_sram += len;
> +
>  	err = 0;
>  
>  err_dma:
> @@ -856,7 +927,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
>  	unsigned long end_time;
>  	int bitflips = 0;
>  
> -	pmecc_enable(host, NAND_ECC_READ);
> +	if (!host->nfc || !host->nfc->use_nfc_sram)
> +		pmecc_enable(host, NAND_ECC_READ);
>  
>  	chip->read_buf(mtd, buf, eccsize);
>  	chip->read_buf(mtd, oob, mtd->oobsize);
> @@ -1669,6 +1741,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  	unsigned int addr1234 = 0;
>  	unsigned int cycle0 = 0;
>  	bool do_addr = true;
> +	host->nfc->data_in_sram = NULL;
>  
>  	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
>  	     __func__, command, column, page_addr);
> @@ -1710,6 +1783,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  			command = NAND_CMD_READ0; /* only READ0 is valid */
>  			cmd1 = command << 2;
>  		}
> +		if (host->nfc->use_nfc_sram) {
> +			/* Enable Data transfer to sram */
> +			dataen = NFCADDR_CMD_DATAEN;
> +
> +			/* Need enable PMECC now, since NFC will transfer
> +			 * data in bus after sending nfc read command.
> +			 */
> +			if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
> +				pmecc_enable(host, NAND_ECC_READ);
> +		}
>  
>  		cmd2 = NAND_CMD_READSTART << 10;
>  		vcmd2 = NFCADDR_CMD_VCMD2;
> @@ -1731,6 +1814,10 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
>  	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
>  
> +	if (dataen == NFCADDR_CMD_DATAEN)
> +		if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
> +			dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
> +
>  	/*
>  	 * Program and erase have their own busy handlers status, sequential
>  	 * in, and deplete1 need no delay.
> @@ -1748,12 +1835,65 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  		return;
>  
>  	case NAND_CMD_READ0:
> +		if (dataen == NFCADDR_CMD_DATAEN) {
> +			host->nfc->data_in_sram = host->nfc->sram_bank0 +
> +				nfc_get_sram_off(host);
> +			return;
> +		}
>  		/* fall through */
>  	default:
>  		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
>  	}
>  }
>  
> +static int nfc_sram_init(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct atmel_nand_host *host = chip->priv;
> +	int res = 0;
> +
> +	/* Initialize the NFC CFG register */
> +	unsigned int cfg_nfc = 0;
> +
> +	/* set page size and oob layout */
> +	switch (mtd->writesize) {
> +	case 512:
> +		cfg_nfc = NFC_CFG_PAGESIZE_512;
> +		break;
> +	case 1024:
> +		cfg_nfc = NFC_CFG_PAGESIZE_1024;
> +		break;
> +	case 2048:
> +		cfg_nfc = NFC_CFG_PAGESIZE_2048;
> +		break;
> +	case 4096:
> +		cfg_nfc = NFC_CFG_PAGESIZE_4096;
> +		break;
> +	case 8192:
> +		cfg_nfc = NFC_CFG_PAGESIZE_8192;
> +		break;
> +	default:
> +		dev_err(host->dev, "Unsupported page size for NFC.\n");
> +		res = -ENXIO;
> +		return res;
> +	}
> +
> +	/* oob bytes size = (NFCSPARESIZE + 1) * 4
> +	 * Max support spare size is 512 bytes. */
> +	cfg_nfc |= (((mtd->oobsize / 4) - 1) << 24 & NFC_CFG_NFC_SPARESIZE);
> +	/* default set a max timeout */
> +	cfg_nfc |= NFC_CFG_RSPARE |
> +			NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
> +
> +	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
> +
> +	nfc_set_sram_bank(host, 0);
> +
> +	dev_info(host->dev, "Using NFC Sram read\n");
> +
> +	return 0;
> +}
> +
>  static struct platform_driver atmel_nand_nfc_driver;
>  /*
>   * Probe for the NAND device.
> @@ -1928,6 +2068,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>  			goto err_hw_ecc;
>  	}
>  
> +	/* initialize the nfc configuration register */
> +	if (host->nfc && host->nfc->use_nfc_sram) {
> +		res = nfc_sram_init(mtd);
> +		if (res) {
> +			host->nfc->use_nfc_sram = false;
> +			dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
> +		}
> +	}
> +
>  	/* second phase scan */
>  	if (nand_scan_tail(mtd)) {
>  		res = -ENXIO;
> @@ -2009,11 +2158,13 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
>  	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
>  	if (nfc_sram) {
>  		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
> -		if (IS_ERR(nfc->sram_bank0))
> +		if (IS_ERR(nfc->sram_bank0)) {
>  			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
>  					PTR_ERR(nfc->sram_bank0));
> -		else
> +		} else {
> +			nfc->use_nfc_sram = true;
>  			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
> +		}
>  	}
>  
>  	nfc->is_initialized = true;
> -- 
> 1.7.9.5
> 


From plagnioj at jcrosoft.com  Wed Jun 12 07:58:20 2013
From: plagnioj at jcrosoft.com (Jean-Christophe PLAGNIOL-VILLARD)
Date: Wed, 12 Jun 2013 13:58:20 +0200
Subject: [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller
 (NFC) write via sram
In-Reply-To: <1370860014-1770-6-git-send-email-josh.wu@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-6-git-send-email-josh.wu@atmel.com>
Message-ID: <20130612115820.GS23653@game.jcrosoft.org>

On 18:26 Mon 10 Jun     , Josh Wu wrote:
> This patch enable writing nand flash via NFC SRAM. It will minimize the CPU
> overhead. The SRAM write only support ECC_NONE and ECC_HW with PMECC.
> 
> To enable this NFC write by SRAM feature, you can add a string in dts under
> NFC driver node.
> 
> This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
> mtd-utils.
> 
> Here is part of mtd_speedtest (writing test) result, compare with non-NFC
> writing, it reduces %65 cpu load with loss %12 speed.
> 
> - commands use to test:
>   # insmod /mnt/mtd_speedtest.ko dev=2 &
>   # top -n 30 -d 1 | grep speedtest
> 
> - test result:
> =================================================
> mtd_speedtest: MTD device: 2
> mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
> mtd_speedtest: testing eraseblock write speed
>   509   495 root     D     1164   0%   7% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%   8% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     R     1164   0%   5% insmod /mnt/mtd_speedtest.ko dev=2
> mtd_speedtest: eraseblock write speed is 5194 KiB/s
> mtd_speedtest: testing page write speed
>   509   495 root     D     1164   0%  32% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  27% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
>   509   495 root     D     1164   0%  30% insmod /mnt/mtd_speedtest.ko dev=2
> mtd_speedtest: page write speed is 5024 KiB/s
> 
> Signed-off-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>

Best Regards,
J.
> ---
> v2 --> v3:
>   - use a property of NFC node to enable/disable NFC write via sram.
> 
>  .../devicetree/bindings/mtd/atmel-nand.txt         |    2 +
>  drivers/mtd/nand/atmel_nand.c                      |  107 ++++++++++++++++++--
>  2 files changed, 103 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
> index 6a267cb..da78e22 100644
> --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
> +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
> @@ -35,6 +35,8 @@ Optional properties:
>      - reg : should specify the address and size used for NFC command registers,
>              NFC registers and NFC Sram. NFC Sram address and size can be absent
>              if don't want to use it.
> +  - Optional properties:
> +    - atmel,write-by-sram: boolean to enable NFC write by sram.
>  
>  Examples:
>  nand0: nand at 40000000,0 {
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index c2ec740..e3e348b 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -97,12 +97,14 @@ struct atmel_nfc {
>  	void __iomem		*sram_bank0;
>  	dma_addr_t		sram_bank0_phys;
>  	bool			use_nfc_sram;
> +	bool			write_by_sram;
>  
>  	bool			is_initialized;
>  	struct completion	comp_nfc;
>  
>  	/* Point to the sram bank which include readed data via NFC */
>  	void __iomem		*data_in_sram;
> +	bool			will_write_sram;
>  };
>  static struct atmel_nfc	nand_nfc;
>  
> @@ -269,6 +271,16 @@ static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
>  		*t++ = readl_relaxed(s++);
>  }
>  
> +static void memcpy32_toio(void __iomem *trg, const void *src, int size)
> +{
> +	int i;
> +	u32 __iomem *t = trg;
> +	const u32 *s = src;
> +
> +	for (i = 0; i < (size >> 2); i++)
> +		writel_relaxed(*s++, t++);
> +}
> +
>  /*
>   * Minimal-overhead PIO for data access.
>   */
> @@ -390,7 +402,11 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
>  		dma_dst_addr = phys_addr;
>  	} else {
>  		dma_src_addr = phys_addr;
> -		dma_dst_addr = host->io_phys;
> +
> +		if (nfc && nfc->write_by_sram)
> +			dma_dst_addr = nfc_sram_phys(host);
> +		else
> +			dma_dst_addr = host->io_phys;
>  	}
>  
>  	tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
> @@ -961,9 +977,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
>  	int i, j;
>  	unsigned long end_time;
>  
> -	pmecc_enable(host, NAND_ECC_WRITE);
> -
> -	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
> +	if (!host->nfc || !host->nfc->write_by_sram) {
> +		pmecc_enable(host, NAND_ECC_WRITE);
> +		chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
> +	}
>  
>  	end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
>  	while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
> @@ -1802,6 +1819,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  	case NAND_CMD_SEQIN:
>  	case NAND_CMD_RNDIN:
>  		nfcwr = NFCADDR_CMD_NFCWR;
> +		if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
> +			dataen = NFCADDR_CMD_DATAEN;
>  		break;
>  	default:
>  		break;
> @@ -1846,6 +1865,68 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>  	}
>  }
>  
> +static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
> +			uint32_t offset, int data_len, const uint8_t *buf,
> +			int oob_required, int page, int cached, int raw)
> +{
> +	int cfg, len;
> +	int status = 0;
> +	struct atmel_nand_host *host = chip->priv;
> +	void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
> +
> +	/* Subpage write is not supported */
> +	if (offset || (data_len < mtd->writesize))
> +		return -EINVAL;
> +
> +	cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
> +	len = mtd->writesize;
> +
> +	if (unlikely(raw)) {
> +		len += mtd->oobsize;
> +		nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
> +	} else
> +		nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
> +
> +	/* Copy page data to sram that will write to nand via NFC */
> +	if (use_dma) {
> +		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
> +			/* Fall back to use cpu copy */
> +			memcpy32_toio(sram, buf, len);
> +	} else {
> +		memcpy32_toio(sram, buf, len);
> +	}
> +
> +	if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
> +		/*
> +		 * When use NFC sram, need set up PMECC before send
> +		 * NAND_CMD_SEQIN command. Since when the nand command
> +		 * is sent, nfc will do transfer from sram and nand.
> +		 */
> +		pmecc_enable(host, NAND_ECC_WRITE);
> +
> +	host->nfc->will_write_sram = true;
> +	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
> +	host->nfc->will_write_sram = false;
> +
> +	if (likely(!raw))
> +		/* Need to write ecc into oob */
> +		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
> +
> +	if (status < 0)
> +		return status;
> +
> +	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
> +	status = chip->waitfunc(mtd, chip);
> +
> +	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
> +		status = chip->errstat(mtd, chip, FL_WRITING, status, page);
> +
> +	if (status & NAND_STATUS_FAIL)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
>  static int nfc_sram_init(struct mtd_info *mtd)
>  {
>  	struct nand_chip *chip = mtd->priv;
> @@ -1887,10 +1968,20 @@ static int nfc_sram_init(struct mtd_info *mtd)
>  
>  	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
>  
> +	host->nfc->will_write_sram = false;
>  	nfc_set_sram_bank(host, 0);
>  
> -	dev_info(host->dev, "Using NFC Sram read\n");
> +	/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
> +	if (host->nfc->write_by_sram) {
> +		if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
> +				chip->ecc.mode == NAND_ECC_NONE)
> +			chip->write_page = nfc_sram_write_page;
> +		else
> +			host->nfc->write_by_sram = false;
> +	}
>  
> +	dev_info(host->dev, "Using NFC Sram read %s\n",
> +			host->nfc->write_by_sram ? "and write" : "");
>  	return 0;
>  }
>  
> @@ -2164,11 +2255,15 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
>  		} else {
>  			nfc->use_nfc_sram = true;
>  			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
> +
> +			if (pdev->dev.of_node)
> +				nfc->write_by_sram = of_property_read_bool(
> +						pdev->dev.of_node,
> +						"atmel,write-by-sram");
>  		}
>  	}
>  
>  	nfc->is_initialized = true;
> -
>  	dev_info(&pdev->dev, "NFC is probed.\n");
>  	return 0;
>  }
> -- 
> 1.7.9.5
> 


From adrian.hunter at intel.com  Wed Jun 12 09:09:41 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 12 Jun 2013 16:09:41 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
Message-ID: <51B87315.7090808@intel.com>

Can you tar and send fs/ubifs directory?

On 12/06/13 14:57, Prins Anton (ST-CO/ENG1.1) wrote:
> Ok clear!
>
> Regarding mount debug: I suppose I only will see this on the 'first' boot after the problem is in the persistence storage?
> (Up to now I'm not able to signal the point-of-failure... I'm only looking to an (possibly) after recovery situation).
>
> Or makes this sense to do this mount debug on the existing failing device?
>
> FYI: 
> - with 100 devices power cycling every 5 minutes for a weekend we DON'T see a problem.
> - with 100 devices powered on for a weekend and after that give a single power-cycle shows maybe 1 or 2 failing devices (but sometimes '0').
>
> So a main problem in analyzing is the 'moment of failure' and 'reproduction (rate)'.
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
>
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
> Sent: woensdag 12 juni 2013 14:00
> To: Prins Anton (ST-CO/ENG1.1)
> Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
> Subject: Re: UBIFS failure & stable page writes
>
> On 12/06/13 14:13, Prins Anton (ST-CO/ENG1.1) wrote:
>> Does it make sense to use chk_orphans?
> That checks for missing orphans but the problem is the opposite: the
> presence of orphans that should not be there.
>
>> I suppose I have to do: $ echo "1" > chk_orphans
>>
>> Or am I wrong?
>>
>> Met vriendelijke groeten | Best Regards, 
>> Anton Prins
>>



From Anton.Prins at nl.bosch.com  Wed Jun 12 09:57:25 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Wed, 12 Jun 2013 15:57:25 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51B87315.7090808@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>

Ofcourse

Met vriendelijke groeten | Best Regards, 
Anton Prins

Bosch Security Systems BV, 
Conference Systems (ST-CO/ENG1.1) 
Torenallee 49
5617 BA  Eindhoven
The Netherlands 
www.boschsecurity.com 
T. +31 (0)40 2577077
anton.prins at nl.bosch.com


-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: woensdag 12 juni 2013 15:10
To: Prins Anton (ST-CO/ENG1.1)
Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
Subject: Re: UBIFS failure & stable page writes

Can you tar and send fs/ubifs directory?

On 12/06/13 14:57, Prins Anton (ST-CO/ENG1.1) wrote:
> Ok clear!
>
> Regarding mount debug: I suppose I only will see this on the 'first' boot after the problem is in the persistence storage?
> (Up to now I'm not able to signal the point-of-failure... I'm only looking to an (possibly) after recovery situation).
>
> Or makes this sense to do this mount debug on the existing failing device?
>
> FYI: 
> - with 100 devices power cycling every 5 minutes for a weekend we DON'T see a problem.
> - with 100 devices powered on for a weekend and after that give a single power-cycle shows maybe 1 or 2 failing devices (but sometimes '0').
>
> So a main problem in analyzing is the 'moment of failure' and 'reproduction (rate)'.
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
>
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
> Sent: woensdag 12 juni 2013 14:00
> To: Prins Anton (ST-CO/ENG1.1)
> Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
> Subject: Re: UBIFS failure & stable page writes
>
> On 12/06/13 14:13, Prins Anton (ST-CO/ENG1.1) wrote:
>> Does it make sense to use chk_orphans?
> That checks for missing orphans but the problem is the opposite: the
> presence of orphans that should not be there.
>
>> I suppose I have to do: $ echo "1" > chk_orphans
>>
>> Or am I wrong?
>>
>> Met vriendelijke groeten | Best Regards, 
>> Anton Prins
>>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: ubifs.tar.gz
Type: application/x-gzip
Size: 711660 bytes
Desc: ubifs.tar.gz
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130612/8035b0c9/attachment-0001.bin>

From tony at atomide.com  Wed Jun 12 13:01:27 2013
From: tony at atomide.com (Tony Lindgren)
Date: Wed, 12 Jun 2013 10:01:27 -0700
Subject: [PATCH v4 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371034858-19984-3-git-send-email-pekon@ti.com>
References: <1371034858-19984-1-git-send-email-pekon@ti.com>
 <1371034858-19984-3-git-send-email-pekon@ti.com>
Message-ID: <20130612170126.GI8164@atomide.com>

* Pekon Gupta <pekon at ti.com> [130612 04:07]:
> From: avinash philip <avinashphilip at ti.com>
> 
> With GPMC converted to platform driver recently, adds low power
> transition support in driver itself.

Applying the first two patches of this series into omap-for-v3.11/gpmc.
Not taking the MTD patch, if it has dependencies to the first two
patches please let me know and also get an ack from Artem if you
want me to take it.

Regards,

Tony


From tony at atomide.com  Wed Jun 12 13:38:54 2013
From: tony at atomide.com (Tony Lindgren)
Date: Wed, 12 Jun 2013 10:38:54 -0700
Subject: [PATCH v4 2/3] arm: gpmc: Low power transition support
In-Reply-To: <20130612170126.GI8164@atomide.com>
References: <1371034858-19984-1-git-send-email-pekon@ti.com>
 <1371034858-19984-3-git-send-email-pekon@ti.com>
 <20130612170126.GI8164@atomide.com>
Message-ID: <20130612173854.GP8164@atomide.com>

* Tony Lindgren <tony at atomide.com> [130612 10:08]:
> * Pekon Gupta <pekon at ti.com> [130612 04:07]:
> > From: avinash philip <avinashphilip at ti.com>
> > 
> > With GPMC converted to platform driver recently, adds low power
> > transition support in driver itself.
> 
> Applying the first two patches of this series into omap-for-v3.11/gpmc.
> Not taking the MTD patch, if it has dependencies to the first two
> patches please let me know and also get an ack from Artem if you
> want me to take it.

Oops, dropping the second patch in this series as it causes the
following if only omap4 is selected for example:

arch/arm/mach-omap2/built-in.o: In function `gpmc_resume':
dss-common.c:(.text+0x9a8): undefined reference to `omap3_gpmc_restore_context'
arch/arm/mach-omap2/built-in.o: In function `gpmc_suspend':
dss-common.c:(.text+0x9c8): undefined reference to `omap3_gpmc_save_context'

Can you please take a lok and fix that?

Regards,

Tony


From josh.wu at atmel.com  Wed Jun 12 21:59:21 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Thu, 13 Jun 2013 09:59:21 +0800
Subject: [PATCH 3/6] mtd: atmel_nand: add Nand Flash Controller (NFC)
 support
In-Reply-To: <20130610132211.GO23653@game.jcrosoft.org>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-4-git-send-email-josh.wu@atmel.com>
 <20130610132211.GO23653@game.jcrosoft.org>
Message-ID: <51B92779.8030309@atmel.com>

Hi, Jean-Christophe PLAGNIOL-VILLARD

On 6/10/2013 9:22 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> +
>>   /*
>>    * Minimal-overhead PIO for data access.
>>    */
>> @@ -1341,6 +1409,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
>>   
>>   	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
>>   
>> +	/* load the nfc driver if there is */
>> +	of_platform_populate(np, NULL, NULL, host->dev);
> what is this?????

Here I call of_platform_populate() to make sure the NFC driver's probe 
function is called.

In this version, in the dts file, the NFC device node is as sub-node of 
Atmel NAND device like:

nand0: nand at 40000000 {
     compatible = "atmel,at91rm9200-nand";
     #address-cells = <1>;
     #size-cells = <1>;
     ranges;
         ...
         nfc at 70000000 {
         compatible = "atmel,sama5d3-nfc";
            reg =  <
                       ...
                       >;
         };


So when NAND driver is probed, It will populate its sub-node (i.e NFC 
device node). And this make
sure after the function (atmel_of_init_port) is called and the NFC 
driver's probe function is already
called and NFC resources should be initialized.

>
>
>> +
>>   	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
>>   		return 0;	/* Not using PMECC */
>>   
>> @@ -1452,6 +1523,238 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
>>   	return 0;
>>   }
>>   
>> +/* SMC interrupt service routine */
>> +static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
>> +{
>> +	struct atmel_nand_host *host = dev_id;
>> +	u32 status, mask, pending;
>> +	irqreturn_t ret = IRQ_HANDLED;
>> +
>> +	status = nfc_readl(host->nfc->hsmc_regs, SR);
>> +	mask = nfc_readl(host->nfc->hsmc_regs, IMR);
>> +	pending = status & mask;
>> +
>> +	if (pending & NFC_SR_XFR_DONE) {
>> +		complete(&host->nfc->comp_nfc);
>> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
>> +	} else if (pending & NFC_SR_RB_EDGE) {
>> +		complete(&host->nfc->comp_nfc);
>> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
>> +	} else if (pending & NFC_SR_CMD_DONE) {
>> +		complete(&host->nfc->comp_nfc);
>> +		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
>> +	} else {
>> +		ret = IRQ_NONE;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +/* NFC(Nand Flash Controller) related functions */
>> +static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
>> +{
>> +	unsigned long timeout;
>> +	init_completion(&host->nfc->comp_nfc);
>> +
>> +	/* Enable interrupt that need to wait for */
>> +	nfc_writel(host->nfc->hsmc_regs, IER, flag);
>> +
>> +	timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
>> +			msecs_to_jiffies(NFC_TIME_OUT_MS));
>> +	if (timeout)
>> +		return 0;
>> +
>> +	/* Time out to wait for the interrupt */
>> +	dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int nfc_send_command(struct atmel_nand_host *host,
>> +	unsigned int cmd, unsigned int addr, unsigned char cycle0)
>> +{
>> +	unsigned long timeout;
>> +	dev_dbg(host->dev,
>> +		"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
>> +		cmd, addr, cycle0);
>> +
>> +	timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
>> +	while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
>> +			& NFCADDR_CMD_NFCBUSY) {
>> +		if (time_after(jiffies, timeout)) {
>> +			dev_err(host->dev,
>> +				"Time out to wait CMD_NFCBUSY ready!\n");
>> +			return -ETIMEDOUT;
>> +		}
>> +	}
>> +	nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
>> +	nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
>> +	return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
>> +}
>> +
>> +static int nfc_device_ready(struct mtd_info *mtd)
>> +{
>> +	struct nand_chip *nand_chip = mtd->priv;
>> +	struct atmel_nand_host *host = nand_chip->priv;
>> +	if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
>> +		return 1;
>> +	return 0;
>> +}
>> +
>> +static void nfc_select_chip(struct mtd_info *mtd, int chip)
>> +{
>> +	struct nand_chip *nand_chip = mtd->priv;
>> +	struct atmel_nand_host *host = nand_chip->priv;
>> +
>> +	if (chip == -1)
>> +		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
>> +	else
>> +		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
>> +}
>> +
>> +static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
>> +		unsigned int *addr1234, unsigned int *cycle0)
>> +{
>> +	struct nand_chip *chip = mtd->priv;
>> +
>> +	int acycle = 0;
>> +	unsigned char addr_bytes[8];
>> +	int index = 0, bit_shift;
>> +
>> +	BUG_ON(addr1234 == NULL || cycle0 == NULL);
>> +
>> +	*cycle0 = 0;
>> +	*addr1234 = 0;
>> +
>> +	if (column != -1) {
>> +		if (chip->options & NAND_BUSWIDTH_16)
>> +			column >>= 1;
>> +		addr_bytes[acycle++] = column & 0xff;
>> +		if (mtd->writesize > 512)
>> +			addr_bytes[acycle++] = (column >> 8) & 0xff;
>> +	}
>> +
>> +	if (page_addr != -1) {
>> +		addr_bytes[acycle++] = page_addr & 0xff;
>> +		addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
>> +		if (chip->chipsize > (128 << 20))
>> +			addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
>> +	}
>> +
>> +	if (acycle > 4)
>> +		*cycle0 = addr_bytes[index++];
>> +
>> +	for (bit_shift = 0; index < acycle; bit_shift += 8)
>> +		*addr1234 += addr_bytes[index++] << bit_shift;
>> +
>> +	return acycle << 19;	/* return acycle in cmd register */
>> +}
>> +
>> +static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
>> +				int column, int page_addr)
>> +{
>> +	struct nand_chip *chip = mtd->priv;
>> +	struct atmel_nand_host *host = chip->priv;
>> +	unsigned long timeout;
>> +	unsigned int nfc_addr_cmd = 0;
>> +
>> +	unsigned int cmd1 = command << 2;
>> +
>> +	/* Set default settings: no cmd2, no addr cycle. read from nand */
>> +	unsigned int cmd2 = 0;
>> +	unsigned int vcmd2 = 0;
>> +	int acycle = NFCADDR_CMD_ACYCLE_NONE;
>> +	int csid = NFCADDR_CMD_CSID_3;
>> +	int dataen = NFCADDR_CMD_DATADIS;
>> +	int nfcwr = NFCADDR_CMD_NFCRD;
>> +	unsigned int addr1234 = 0;
>> +	unsigned int cycle0 = 0;
>> +	bool do_addr = true;
>> +
>> +	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
>> +	     __func__, command, column, page_addr);
>> +
>> +	switch (command) {
>> +	case NAND_CMD_RESET:
>> +		nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
>> +		nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
>> +		udelay(chip->chip_delay);
>> +
>> +		nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
>> +		timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
>> +		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
>> +			if (time_after(jiffies, timeout)) {
>> +				dev_err(host->dev,
>> +					"Time out to wait status ready!\n");
>> +				break;
>> +			}
>> +		}
>> +		return;
>> +	case NAND_CMD_STATUS:
>> +		do_addr = false;
>> +		break;
>> +	case NAND_CMD_PARAM:
>> +	case NAND_CMD_READID:
>> +		do_addr = false;
>> +		acycle = NFCADDR_CMD_ACYCLE_1;
>> +		if (column != -1)
>> +			addr1234 = column;
>> +		break;
>> +	case NAND_CMD_RNDOUT:
>> +		cmd2 = NAND_CMD_RNDOUTSTART << 10;
>> +		vcmd2 = NFCADDR_CMD_VCMD2;
>> +		break;
>> +	case NAND_CMD_READ0:
>> +	case NAND_CMD_READOOB:
>> +		if (command == NAND_CMD_READOOB) {
>> +			column += mtd->writesize;
>> +			command = NAND_CMD_READ0; /* only READ0 is valid */
>> +			cmd1 = command << 2;
>> +		}
>> +
>> +		cmd2 = NAND_CMD_READSTART << 10;
>> +		vcmd2 = NFCADDR_CMD_VCMD2;
>> +		break;
>> +	/* For prgramming command, the cmd need set to write enable */
>> +	case NAND_CMD_PAGEPROG:
>> +	case NAND_CMD_SEQIN:
>> +	case NAND_CMD_RNDIN:
>> +		nfcwr = NFCADDR_CMD_NFCWR;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (do_addr)
>> +		acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
>> +				&cycle0);
>> +
>> +	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
>> +	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
>> +
>> +	/*
>> +	 * Program and erase have their own busy handlers status, sequential
>> +	 * in, and deplete1 need no delay.
>> +	 */
>> +	switch (command) {
>> +	case NAND_CMD_CACHEDPROG:
>> +	case NAND_CMD_PAGEPROG:
>> +	case NAND_CMD_ERASE1:
>> +	case NAND_CMD_ERASE2:
>> +	case NAND_CMD_RNDIN:
>> +	case NAND_CMD_STATUS:
>> +	case NAND_CMD_RNDOUT:
>> +	case NAND_CMD_SEQIN:
>> +	case NAND_CMD_READID:
>> +		return;
>> +
>> +	case NAND_CMD_READ0:
>> +		/* fall through */
>> +	default:
>> +		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
>> +	}
>> +}
>> +
>> +static struct platform_driver atmel_nand_nfc_driver;
>>   /*
>>    * Probe for the NAND device.
>>    */
>> @@ -1462,7 +1765,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>>   	struct nand_chip *nand_chip;
>>   	struct resource *mem;
>>   	struct mtd_part_parser_data ppdata = {};
>> -	int res;
>> +	int res, irq;
>>   	struct pinctrl *pinctrl;
>>   
>>   	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> @@ -1478,6 +1781,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>>   		return -ENOMEM;
>>   	}
>>   
>> +	res = platform_driver_register(&atmel_nand_nfc_driver);
>> +	if (res)
>> +		printk(KERN_ERR "atmel_nand: can't register NFC driver\n");
>> +
> and this????

Did you mean the printk()?

Sorry, I forgot to replace the printk() function, I willuse dev_err() in 
next version.

Best Regards,
Josh Wu

>>   	host->io_base = devm_request_and_ioremap(&pdev->dev, mem);
>>   	if (host->io_base == NULL) {
>>   		printk(KERN_ERR "atmel_nand: ioremap failed\n");
>> @@ -1505,7 +1812,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>>   	/* Set address of NAND IO lines */
>>   	nand_chip->IO_ADDR_R = host->io_base;
>>   	nand_chip->IO_ADDR_W = host->io_base;
>> -	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
>>   
>>   	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
>>   	if (IS_ERR(pinctrl)) {
>> @@ -1514,44 +1820,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
>>   		goto err_nand_ioremap;
>>   	}
>>   
> Best Regards,
> J.



From josh.wu at atmel.com  Wed Jun 12 23:38:39 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Thu, 13 Jun 2013 11:38:39 +0800
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <CAN8TOE-JuVAAKBR84cbs9Hge+bQ6hQpFyoSDywKvCMe7h+Lc4g@mail.gmail.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
 <CAN8TOE-JuVAAKBR84cbs9Hge+bQ6hQpFyoSDywKvCMe7h+Lc4g@mail.gmail.com>
Message-ID: <51B93EBF.5050207@atmel.com>

Hi, Brian

On 6/12/2013 7:34 AM, Brian Norris wrote:
> Hi Josh,
>
> On Mon, Jun 10, 2013 at 3:26 AM, Josh Wu <josh.wu at atmel.com> wrote:
>> If the child node has compatible property then it is a driver not partition.
>>
>> Signed-off-by: Josh Wu <josh.wu at atmel.com>
>> ---
>>   drivers/mtd/ofpart.c |   14 +++++++++++++-
>>   1 file changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
>> index 553d6d6..61ce1f8 100644
>> --- a/drivers/mtd/ofpart.c
>> +++ b/drivers/mtd/ofpart.c
>> @@ -20,6 +20,10 @@
>>   #include <linux/slab.h>
>>   #include <linux/mtd/partitions.h>
>>
>> +static bool node_has_compatible(struct device_node *pp, int *len)
>> +{
>> +       return of_get_property(pp, "compatible", len);
>> +}
> The way the interface is named, it seems like a user only would ever
> need the bool return value, not the implicit 'len' return value. So I
> would write it like this:
>
> static bool node_has_compatible(struct device_node *pp)
> {
>         return of_get_property(pp, "compatible", NULL);
> }

yes, this is exactly is what I want. I didn't check the *len can be NULL 
or not. thanks.

>
>>   static int parse_ofpart_partitions(struct mtd_info *master,
>>                                     struct mtd_partition **pparts,
>>                                     struct mtd_part_parser_data *data)
>> @@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>>          /* First count the subnodes */
>>          pp = NULL;
>>          nr_parts = 0;
>> -       while ((pp = of_get_next_child(node, pp)))
>> +       while ((pp = of_get_next_child(node, pp))) {
>> +               int len;
>> +               if (node_has_compatible(pp, &len))
> Then this would just be:
>
> if (node_has_compatible(pp))
> ...
> etc. (rest snipped)
>
> On a more important question, why does a NAND device node have
> sub-nodes that are not partitions? And if such devices exist, wouldn't
> it be more foolproof to establish a "compatible" property for ofpart
> partitions?

In my case, we have a Atmel NAND flash driver/device which is work for 
all series of SAM9/SAMA5D3 chip.
And since in the new chip SAMA5D3 which has a NAND Flash Controller support.

So to enable NAND flash controller, I should either write a compatible 
driver like atmel,sama5-nand, which is
just old device property plus NFC regs and NFC properties, that became 
too big. Or add a NFC sub-node for the NFC support.

IMHO, to make the NFC device as a sub-node is the simplest way to make 
nand driver is back-compatible and easy to enable/disable NFC feature.
Since all NFC related property are grouped it is more readable.

But to implement this, I need to add this patch, otherwise this NFC sub 
node will be recognized as a partition.

> Of course, we'd still have to retain
> backward-compatibility and allow partitions without a "compatible"
> prop. But this question probably should be addressed in the commit log
> and documented in Documentation/devicetree/bindings/mtd/partition.txt
> ; either specifying that all sub-nodes without a compatible property
> must be partitions, or else some other explanation.

yes, sure. I will add an explanation in commit log and 
Documentation/devicetree/bindings/mtd/partition.txt in next version.

>
> Brian

Best Regards,
Josh Wu


From josh.wu at atmel.com  Wed Jun 12 23:42:26 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Thu, 13 Jun 2013 11:42:26 +0800
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <51B5C80D.2030303@cogentembedded.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
 <51B5C80D.2030303@cogentembedded.com>
Message-ID: <51B93FA2.7040206@atmel.com>

Hi, Sergei

On 6/10/2013 8:35 PM, Sergei Shtylyov wrote:
> hello.
>
> On 10-06-2013 14:26, Josh Wu wrote:
>
>> If the child node has compatible property then it is a driver not 
>> partition.
>
>> Signed-off-by: Josh Wu <josh.wu at atmel.com>
>> ---
>>   drivers/mtd/ofpart.c |   14 +++++++++++++-
>>   1 file changed, 13 insertions(+), 1 deletion(-)
>
>
>> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
>> index 553d6d6..61ce1f8 100644
>> --- a/drivers/mtd/ofpart.c
>> +++ b/drivers/mtd/ofpart.c
> [...]
>> @@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info 
>> *master,
>>       /* First count the subnodes */
>>       pp = NULL;
>>       nr_parts = 0;
>> -    while ((pp = of_get_next_child(node, pp)))
>> +    while ((pp = of_get_next_child(node, pp))) {
>
>    Assignment in *while*? Is scripts/checkpatch.pl happy about that?

yes, checkpatch.pl has no complain  ;-)

>
>> +        int len;
>
>    Empty line wouldn't hurt here, after declaration.

Ok, as Brian said, I will no need to use a 'int len' here. So I will 
remove those declaration.

>
>> +        if (node_has_compatible(pp, &len))
>> +            continue;
>> +
>>           nr_parts++;
>> +    }
>>
>>       if (nr_parts == 0)
>>           return 0;
>
> WBR, Sergei
>

Thanks.
Best Regards,
Josh Wu


From adrian.hunter at intel.com  Thu Jun 13 03:41:53 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Thu, 13 Jun 2013 10:41:53 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DD7F@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <4BE1E71893EF1E4F9E9DD99FB4EBF0032C02EA2D44@SI-MBX02.de.bosch.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBA85@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DD7F@SI-MBX14.de.bosch.com>
Message-ID: <51B977C1.4090200@intel.com>

On 28/05/13 16:00, Prins Anton (ST-CO/ENG1.1) wrote:
> Could there be a relation between the issue and the following commits (freeing of orphans/cnext=NULL)?:
>
> http://git.infradead.org/ubifs-2.6.git/commit/8afd500cb52a5d00bab4525dd5a560d199f979b9
> http://git.infradead.org/ubifs-2.6.git/commit/2928f0d0c5ebd6c9605c0d98207a44376387c298

Yes you do have the problem that these patches fix.  Please try them.

>
>
> Met vriendelijke groeten | Best Regards, 
> Anton Prins
>
> Bosch Security Systems BV, 
> Conference Systems (ST-CO/ENG1.1) 
> Torenallee 49
> 5617 BA  Eindhoven
> The Netherlands 
> www.boschsecurity.com 
> T. +31 (0)40 2577077
> anton.prins at nl.bosch.com
>
>
> -----Original Message-----
> From: Artem Bityutskiy [mailto:dedekind1 at gmail.com] 
> Sent: dinsdag 28 mei 2013 11:11
> To: Prins Anton (ST-CO/ENG1.1)
> Cc: Jan Kara; Adrian Hunter; linux-mtd at lists.infradead.org
> Subject: Re: UBIFS failure & stable page writes
>
> On Tue, 2013-05-28 at 10:18 +0200, Prins Anton (ST-CO/ENG1.1) wrote:
>> Creation is of the problem is not that easy, but once you boot and this happens it is reproducible every boot.
>> Even if I copy the image (nanddump) to another device the failure moves with the image.
> Well, the latter is less interesting.
>



From Mats.Karrman at tritech.se  Thu Jun 13 06:54:15 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 13 Jun 2013 10:54:15 +0000
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>

Hi!

Joining in from thread "UBIFS Orphaned inode 1" since it's the same problem.
This is an orphans block from one of my crashed units:

=== Orphan nodes (LEB 9) ===

$ dd if=/dev/ubi0_0 bs=1 count=130944 skip=1178496 |hd
00000000  31 18 10 06 a9 ec d2 ed  c8 f6 6a 01 00 00 00 00  |1.........j.....|
00000010  30 00 00 00 0b 00 00 00  a4 06 00 00 00 00 00 80  |0...............|
00000020  14 72 12 00 00 00 00 00  01 00 00 00 00 00 00 00  |.r..............|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
0001ff80

Decoded:
31 18 10 06 - UBIFS_NODE_MAGIC
a9 ec d2 ed - CRC
c8 f6 6a 01 00 00 00 00 - Sequence number
30 00 00 00 - node length = 48 bytes
0b - node type = Orphan node
00 - group type = Not part of group
00 00 - padding
a4 06 00 00 00 00 00 80 - commit number = 0x6a4, last node flag = set
14 72 12 00 00 00 00 00 - inode num = 0x127214
01 00 00 00 00 00 00 00 - inode num = 1 !!!

I have v2.6.35 with a lot of patches from Artem's maintenance tree and some more from the later developments.
I diffed my fs/ubifs to the files from Antion Prins and they are almost identical, mostly debug print changes and some small things that I think are unrelated.

I have not been able to reproduce the error but haven't got the resources to set up 100 test units. So far a hand-full of units has crashed in the field.

BR // Mats


________________________________________
From: linux-mtd [linux-mtd-bounces at lists.infradead.org] on behalf of Prins Anton (ST-CO/ENG1.1) [Anton.Prins at nl.bosch.com]
Sent: Wednesday, June 12, 2013 3:57 PM
To: Adrian Hunter
Cc: linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: RE: UBIFS failure & stable page writes

Ofcourse

Met vriendelijke groeten | Best Regards,
Anton Prins

Bosch Security Systems BV,
Conference Systems (ST-CO/ENG1.1)
Torenallee 49
5617 BA  Eindhoven
The Netherlands
www.boschsecurity.com
T. +31 (0)40 2577077
anton.prins at nl.bosch.com


-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com]
Sent: woensdag 12 juni 2013 15:10
To: Prins Anton (ST-CO/ENG1.1)
Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
Subject: Re: UBIFS failure & stable page writes

Can you tar and send fs/ubifs directory?

On 12/06/13 14:57, Prins Anton (ST-CO/ENG1.1) wrote:
> Ok clear!
>
> Regarding mount debug: I suppose I only will see this on the 'first' boot after the problem is in the persistence storage?
> (Up to now I'm not able to signal the point-of-failure... I'm only looking to an (possibly) after recovery situation).
>
> Or makes this sense to do this mount debug on the existing failing device?
>
> FYI:
> - with 100 devices power cycling every 5 minutes for a weekend we DON'T see a problem.
> - with 100 devices powered on for a weekend and after that give a single power-cycle shows maybe 1 or 2 failing devices (but sometimes '0').
>
> So a main problem in analyzing is the 'moment of failure' and 'reproduction (rate)'.
>
> Met vriendelijke groeten | Best Regards,
> Anton Prins
>
> Met vriendelijke groeten | Best Regards,
> Anton Prins
>
>
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com]
> Sent: woensdag 12 juni 2013 14:00
> To: Prins Anton (ST-CO/ENG1.1)
> Cc: dedekind1 at gmail.com; linux-mtd at lists.infradead.org
> Subject: Re: UBIFS failure & stable page writes
>
> On 12/06/13 14:13, Prins Anton (ST-CO/ENG1.1) wrote:
>> Does it make sense to use chk_orphans?
> That checks for missing orphans but the problem is the opposite: the
> presence of orphans that should not be there.
>
>> I suppose I have to do: $ echo "1" > chk_orphans
>>
>> Or am I wrong?
>>
>> Met vriendelijke groeten | Best Regards,
>> Anton Prins
>>



From helmut.raiger at hale.at  Thu Jun 13 07:42:18 2013
From: helmut.raiger at hale.at (Helmut Raiger)
Date: Thu, 13 Jun 2013 13:42:18 +0200
Subject: UBIFS: How to reserve space to be used right before power cut
Message-ID: <51B9B01A.1090504@hale.at>

Hi,

     we try the following:

1) setup some data in an 8kByte block in RAM
2) frequently modify this data during normal operation
3) on a power fail signal write the block to a file on an UBIFS partition
4) recover from the written data after the power cut

   The time between power failure notification and the uP-reset is 
guaranteed by hardware
and is about 20ms.

We first thought about using fallocate() to allocate a corresponding 
block on the partition
but soon found that UBIFS does not implement a native fallocate() and 
thus the generic
one simply wrote the file to 8k of zeros. This of course will not help.

Simply fsync()ing the file in case of a power cut does not seem 
reliable, for
   - the file system might be full
   - write back cache operation may interfere with the synch-ing of our file
   - the garbage collector might run to free dirty LEBs and erase the 
corresponding PEBs
The latter 2 overstretching our timing requirements.

This is on an embedded system (i.mx31, arm1136 at 532MHz) running Linux 
3.something
(we are quite flexible in adapting new kernel versions), currently 
testing on 3.0.45.

Could someone hint the course to follow for this szenario?

Any pointers appreciated,
Helmut


--
Scanned by MailScanner.



From matthieu.castet at parrot.com  Thu Jun 13 07:50:31 2013
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Thu, 13 Jun 2013 13:50:31 +0200
Subject: UBIFS: How to reserve space to be used right before power cut
In-Reply-To: <51B9B01A.1090504@hale.at>
References: <51B9B01A.1090504@hale.at>
Message-ID: <20130613135031.59037201@parrot.com>

Hi,

Why do you do this in ubifs ?

If you do it in ubi/mtd this will be a lot's of easier.



Matthieu


Le Thu, 13 Jun 2013 12:42:18 +0100,
Helmut Raiger <helmut.raiger at hale.at> a ?crit :

> Hi,
> 
>      we try the following:
> 
> 1) setup some data in an 8kByte block in RAM
> 2) frequently modify this data during normal operation
> 3) on a power fail signal write the block to a file on an UBIFS
> partition 4) recover from the written data after the power cut
> 
>    The time between power failure notification and the uP-reset is 
> guaranteed by hardware
> and is about 20ms.
> 
> We first thought about using fallocate() to allocate a corresponding 
> block on the partition
> but soon found that UBIFS does not implement a native fallocate() and 
> thus the generic
> one simply wrote the file to 8k of zeros. This of course will not
> help.
> 
> Simply fsync()ing the file in case of a power cut does not seem 
> reliable, for
>    - the file system might be full
>    - write back cache operation may interfere with the synch-ing of
> our file
>    - the garbage collector might run to free dirty LEBs and erase the 
> corresponding PEBs
> The latter 2 overstretching our timing requirements.
> 
> This is on an embedded system (i.mx31, arm1136 at 532MHz) running Linux 
> 3.something
> (we are quite flexible in adapting new kernel versions), currently 
> testing on 3.0.45.
> 
> Could someone hint the course to follow for this szenario?
> 
> Any pointers appreciated,
> Helmut
> 
> 
> --
> Scanned by MailScanner.
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



From sergei.shtylyov at cogentembedded.com  Thu Jun 13 09:13:43 2013
From: sergei.shtylyov at cogentembedded.com (Sergei Shtylyov)
Date: Thu, 13 Jun 2013 17:13:43 +0400
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <51B93FA2.7040206@atmel.com>
References: <1370860014-1770-1-git-send-email-josh.wu@atmel.com>
 <1370860014-1770-7-git-send-email-josh.wu@atmel.com>
 <51B5C80D.2030303@cogentembedded.com> <51B93FA2.7040206@atmel.com>
Message-ID: <51B9C587.4020307@cogentembedded.com>

Hello.

On 13-06-2013 7:42, Josh Wu wrote:

>>> If the child node has compatible property then it is a driver not
>>> partition.

>>> Signed-off-by: Josh Wu <josh.wu at atmel.com>
>>> ---
>>>   drivers/mtd/ofpart.c |   14 +++++++++++++-
>>>   1 file changed, 13 insertions(+), 1 deletion(-)


>>> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
>>> index 553d6d6..61ce1f8 100644
>>> --- a/drivers/mtd/ofpart.c
>>> +++ b/drivers/mtd/ofpart.c
>> [...]
>>> @@ -40,8 +44,13 @@ static int parse_ofpart_partitions(struct mtd_info
>>> *master,
>>>       /* First count the subnodes */
>>>       pp = NULL;
>>>       nr_parts = 0;
>>> -    while ((pp = of_get_next_child(node, pp)))
>>> +    while ((pp = of_get_next_child(node, pp))) {

>>    Assignment in *while*? Is scripts/checkpatch.pl happy about that?

> yes, checkpatch.pl has no complain  ;-)

    It seems checkpatch.pl only complains about *if*. Not very consistent...

WBR, Sergei



From helmut.raiger at hale.at  Thu Jun 13 09:29:24 2013
From: helmut.raiger at hale.at (Raiger Helmut)
Date: Thu, 13 Jun 2013 15:29:24 +0200 (CEST)
Subject: UBIFS: How to reserve space to be used right before power cut
In-Reply-To: <20130613135031.59037201@parrot.com>
Message-ID: <1142745477.330790.1371130164128.JavaMail.root@mail.hale>



> ----- Original Message -----
> From: "Matthieu CASTET" <matthieu.castet at parrot.com>
> To: "Helmut Raiger" <helmut.raiger at hale.at>
> Cc: linux-mtd at lists.infradead.org
> Sent: Thursday, June 13, 2013 1:50:31 PM
> Subject: Re: UBIFS: How to reserve space to be used right before power cut
>
> Hi,
>
> Why do you do this in ubifs ?
>
> If you do it in ubi/mtd this will be a lot's of easier.
>
> Matthieu

I wasn't aware of an userspace interface for ubi/mtd, but just found out
about gluebi. Is this the path you suggest?

Could you please elaborate a bit more on this, I'm still unsure if
this will meet our timing constraints (background operation of ubi?)

Helmut

--
Scanned by MailScanner.



From Anton.Prins at nl.bosch.com  Thu Jun 13 09:31:58 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Thu, 13 Jun 2013 15:31:58 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>

We decided not to patch for this weekend, but onlty make an additional logging in UBIFS:

diff -purN a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
--- a/fs/ubifs/orphan.c	2013-06-13 12:19:58.490931170 +0200
+++ b/fs/ubifs/orphan.c	2013-06-13 12:17:13.014931462 +0200
@@ -300,6 +300,9 @@ static int write_orph_node(struct ubifs_
 	for (i = 0; i < cnt; i++) {
 		orphan = cnext;
 		orph->inos[i] = cpu_to_le64(orphan->inum);
+		if (orph->inos[i] < UBIFS_FIRST_INO) {
+			printk(KERN_ERR "ERROR: Wrong ino in orphan list[%lu]: %lu\n", (unsigned long)i, (unsigned long)orph->inos[i]);
+		}
 		cnext = orphan->cnext;
 		orphan->cnext = NULL;
 	}

This to make sure if UBIFS itself writes a node '0' or '1'... and it is forced by UBI, NAND, Peripheral or NAND-Device.
If there is a relation between logging and failing after reboot it would make sense... Means a lot of analyzing; but we have to find it!

Next step is to apply patches and to test again:
http://git.infradead.org/ubifs-2.6.git/commit/8afd500cb52a5d00bab4525dd5a560d199f979b9
http://git.infradead.org/ubifs-2.6.git/commit/2928f0d0c5ebd6c9605c0d98207a44376387c298

And hopefully we get rid of some unexpected orphan nodes.

How realistic is it that the double orphan free causes our problem?
Mats, are you sure the patches mentioned above are also not in your UBIFS?



From adrian.hunter at intel.com  Thu Jun 13 09:41:14 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Thu, 13 Jun 2013 16:41:14 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>
Message-ID: <51B9CBFA.70103@intel.com>

On 13/06/13 16:31, Prins Anton (ST-CO/ENG1.1) wrote:
> We decided not to patch for this weekend, but onlty make an additional logging in UBIFS:
>
> diff -purN a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
> --- a/fs/ubifs/orphan.c	2013-06-13 12:19:58.490931170 +0200
> +++ b/fs/ubifs/orphan.c	2013-06-13 12:17:13.014931462 +0200
> @@ -300,6 +300,9 @@ static int write_orph_node(struct ubifs_
>  	for (i = 0; i < cnt; i++) {
>  		orphan = cnext;
>  		orph->inos[i] = cpu_to_le64(orphan->inum);
> +		if (orph->inos[i] < UBIFS_FIRST_INO) {
> +			printk(KERN_ERR "ERROR: Wrong ino in orphan list[%lu]: %lu\n", (unsigned long)i, (unsigned long)orph->inos[i]);
> +		}
>  		cnext = orphan->cnext;
>  		orphan->cnext = NULL;
>  	}
>
> This to make sure if UBIFS itself writes a node '0' or '1'... and it is forced by UBI, NAND, Peripheral or NAND-Device.
> If there is a relation between logging and failing after reboot it would make sense... Means a lot of analyzing; but we have to find it!

We know UBIFS writes the '0' or '1' because the CRC is correct.  UBIFS would
complain loudly if it were not.

>
> Next step is to apply patches and to test again:
> http://git.infradead.org/ubifs-2.6.git/commit/8afd500cb52a5d00bab4525dd5a560d199f979b9
> http://git.infradead.org/ubifs-2.6.git/commit/2928f0d0c5ebd6c9605c0d98207a44376387c298
>
> And hopefully we get rid of some unexpected orphan nodes.
>
> How realistic is it that the double orphan free causes our problem?
> Mats, are you sure the patches mentioned above are also not in your UBIFS?
>
>
>



From Anton.Prins at nl.bosch.com  Thu Jun 13 10:02:39 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Thu, 13 Jun 2013 16:02:39 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51B9CBFA.70103@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>
 <51B9CBFA.70103@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3CA7@SI-MBX14.de.bosch.com>

Ah, right! Understood.

Then we will see "inode < UBIFS_FIRST_INO" log messages on Monday, pointing to the devices that are going to fail after reboot!

This will make sense, because once applied the patches, we can check for the 'log message' which makes all more deterministic (and allowes for backtracing at moment of failure instead of looking 'after reboot').

Thanks!

-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: donderdag 13 juni 2013 15:41
To: Prins Anton (ST-CO/ENG1.1)
Cc: Mats K?rrman; linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: Re: UBIFS failure & stable page writes

On 13/06/13 16:31, Prins Anton (ST-CO/ENG1.1) wrote:
> We decided not to patch for this weekend, but onlty make an additional logging in UBIFS:
>
> diff -purN a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
> --- a/fs/ubifs/orphan.c	2013-06-13 12:19:58.490931170 +0200
> +++ b/fs/ubifs/orphan.c	2013-06-13 12:17:13.014931462 +0200
> @@ -300,6 +300,9 @@ static int write_orph_node(struct ubifs_
>  	for (i = 0; i < cnt; i++) {
>  		orphan = cnext;
>  		orph->inos[i] = cpu_to_le64(orphan->inum);
> +		if (orph->inos[i] < UBIFS_FIRST_INO) {
> +			printk(KERN_ERR "ERROR: Wrong ino in orphan list[%lu]: %lu\n", (unsigned long)i, (unsigned long)orph->inos[i]);
> +		}
>  		cnext = orphan->cnext;
>  		orphan->cnext = NULL;
>  	}
>
> This to make sure if UBIFS itself writes a node '0' or '1'... and it is forced by UBI, NAND, Peripheral or NAND-Device.
> If there is a relation between logging and failing after reboot it would make sense... Means a lot of analyzing; but we have to find it!

We know UBIFS writes the '0' or '1' because the CRC is correct.  UBIFS would
complain loudly if it were not.

>
> Next step is to apply patches and to test again:
> http://git.infradead.org/ubifs-2.6.git/commit/8afd500cb52a5d00bab4525dd5a560d199f979b9
> http://git.infradead.org/ubifs-2.6.git/commit/2928f0d0c5ebd6c9605c0d98207a44376387c298
>
> And hopefully we get rid of some unexpected orphan nodes.
>
> How realistic is it that the double orphan free causes our problem?
> Mats, are you sure the patches mentioned above are also not in your UBIFS?
>
>
>



From matthieu.castet at parrot.com  Thu Jun 13 10:20:28 2013
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Thu, 13 Jun 2013 16:20:28 +0200
Subject: UBIFS: How to reserve space to be used right before power cut
In-Reply-To: <1142745477.330790.1371130164128.JavaMail.root@mail.hale>
References: <20130613135031.59037201@parrot.com>
 <1142745477.330790.1371130164128.JavaMail.root@mail.hale>
Message-ID: <20130613162028.3d17bac2@parrot.com>

Le Thu, 13 Jun 2013 14:29:24 +0100,
Raiger Helmut <helmut.raiger at hale.at> a ?crit :

> 
> 
> > ----- Original Message -----
> > From: "Matthieu CASTET" <matthieu.castet at parrot.com>
> > To: "Helmut Raiger" <helmut.raiger at hale.at>
> > Cc: linux-mtd at lists.infradead.org
> > Sent: Thursday, June 13, 2013 1:50:31 PM
> > Subject: Re: UBIFS: How to reserve space to be used right before
> > power cut
> >
> > Hi,
> >
> > Why do you do this in ubifs ?
> >
> > If you do it in ubi/mtd this will be a lot's of easier.
> >
> > Matthieu
> 
> I wasn't aware of an userspace interface for ubi/mtd, but just found
> out about gluebi. Is this the path you suggest?
> 
> Could you please elaborate a bit more on this, I'm still unsure if
> this will meet our timing constraints (background operation of ubi?)
> 

Not gluebi

you have a userspace inferface to ubi : /usr/include/mtd/ubi-user.h


You could create a small ubi volume (dynamic or static) of 1 LEB next to
ubifs (on the same ubi device).
When you start you make sure the LEB have enough space and that the LEB
is mapped.

on a power fail signal you write the LEB with your data. Because the
LEB is already mapped, the write should be imediate.


If the ubi volume is on the same ubi device than ubifs, the wear
leveling will be shared with ubifs.






From today at danbuy.dk  Thu Jun 13 11:19:33 2013
From: today at danbuy.dk (today at danbuy.dk)
Date: Thu, 13 Jun 2013 17:19:33 +0200
Subject: =?windows-1251?Q?=C7=E4=F0=E0=E2=F1=F2=E2=F3=E9=F2=E5?=
Message-ID: <69me144f5w97$04ey535sw6$9298ti9w60@ardesait08>

?? ???????? ????????? ??? ?? ?????? ?????????? ??????? ?? ?????????? ???? ???????? 10-???????? ????? ??? ????! http://goo.gl/0zdP2?/rwLHoWc ??????

??????? ????? - ????, ????? - ??? ??????.


From hiharsh at gmail.com  Thu Jun 13 14:58:43 2013
From: hiharsh at gmail.com (harsh poshtiwala)
Date: Thu, 13 Jun 2013 14:58:43 -0400
Subject: Jffs2 errors
Message-ID: <CA+mubHooA5aaOhOacMUvyt3X4jaK0wm8eu+jR+2nTyM_s4QKEg@mail.gmail.com>

Hi,

I am using TI OMAP AM3517 with Linux 2.6.32.
>From time to time I see errors when I update mtd partitions

i use the following commands
flash_eraseall -j /dev/mtd10
mount -t jffs2 /dev/mtdblock10 /tmp/nand
cd nand
tar -xzf rootfs.tar.gz

the erase operation goes successfully, however I see the following
errors at the time of mount/writing

,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe1018d4. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe101690. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe10144c. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe101208. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe100fc4. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe100d80. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe100b3c. {ffff,ffff,ffffffff,ffffffff}
JFFS2 notice: (429) jffs2_get_inode_nodes: Node header CRC failed at
0xe100000. {ffff,ffff,ffffffff,ffffffff}

and finally, I see the following messages before I get the command prompt

JFFS2 warning: (429) jffs2_do_read_inode_internal: no data nodes found
for ino #11487
Returned error for crccheck of ino #11487. Expect badness...
Header CRC failed on REF_PRISTINE node at 0x11f57414: Read 0xffffffff,
calculated 0x44660075
Header CRC failed on REF_PRISTINE node at 0x11f57ba8: Read 0xffffffff,
calculated 0x44660075
Header CRC failed on REF_PRISTINE node at 0x11f5abfc: Read 0xffffffff,
calculated 0x44660075
Node CRC ffffffff != calculated CRC f09e7845 for node at 11f5adfc
read of old metadata failed in jffs2_garbage_collect_metadata(): -5
Error garbage collecting node at 11f5adfc!
No space for garbage collection. Aborting GC thread
Node CRC ffffffff != calculated CRC f09e7845 for node at 11f5adfc
read of old metadata failed in jffs2_garbage_collect_metadata(): -5
Error garbage collecting node at 11f5adfc!
Node CRC ffffffff != calculated CRC f09e7845 for node at 11f5adfc
read of old metadata failed in jffs2_garbage_collect_metadata(): -5
Error garbage collecting node at 11f5adfc!
Node CRC ffffffff != calculated CRC f09e7845 for node at 11f5adfc
read of old metadata failed in jffs2_garbage_collect_metadata(): -5
Error garbage collecting node at 11f5adfc!


One more thing I found is that the target keeps throwing the following messages.
root at ti-omap3-am3517-evm:/tmp# Node CRC ffffffff != calculated CRC
f09e7845 for node at 11f5adfc
read of old metadata failed in jffs2_garbage_collect_metadata(): -5
Error garbage collecting node at 11f5adfc!

Also, when I type some of the commands it fails with the errors

root at ti-omap3-am3517-evm:/tmp# umount nand
JFFS2 warning: (1183) jffs2_get_inode_nodes: Eep. No valid nodes for ino #11253.
JFFS2 warning: (1183) jffs2_do_read_inode_internal: no data nodes
found for ino #11253
iget() failed for ino #11253
-bash: umount: command not found


I would really appreciate your comments to fix this.

--
Thanks & Regards
Harsh


From Anton.Prins at nl.bosch.com  Thu Jun 13 15:24:34 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Thu, 13 Jun 2013 21:24:34 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>

Hi Mats,

Some questions to get more feeling with our problem:

1. Does your application add/remove files (delete/unlink?)
2. Does your kernel run on a single or multi-core machine?
3. Do you experience it with an ungraceful shutdown or also graceful?

The statistics we see is that rebooting every 5 minutes will not give higher occurrence.
It seems that device turned on for a longer time have more chance to fail; but as said not predictable.



From khilman at linaro.org  Thu Jun 13 16:19:58 2013
From: khilman at linaro.org (Kevin Hilman)
Date: Thu, 13 Jun 2013 13:19:58 -0700
Subject: [v4 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371032708-9242-3-git-send-email-pekon@ti.com> (Pekon Gupta's
 message of "Wed, 12 Jun 2013 15:55:07 +0530")
References: <1371032708-9242-1-git-send-email-pekon@ti.com>
 <1371032708-9242-3-git-send-email-pekon@ti.com>
Message-ID: <87bo79bw5t.fsf@linaro.org>

Pekon Gupta <pekon at ti.com> writes:

> From: avinash philip <avinashphilip at ti.com>
>
> With GPMC converted to platform driver recently, adds low power
> transition support in driver itself.

The subject/changelog should be clear that this is support for
suspend/resume.

Kevin


From khilman at linaro.org  Thu Jun 13 17:03:38 2013
From: khilman at linaro.org (Kevin Hilman)
Date: Thu, 13 Jun 2013 14:03:38 -0700
Subject: [v4 3/3] mtd: devices: elm: Low power transition support
In-Reply-To: <1371032708-9242-4-git-send-email-pekon@ti.com> (Pekon Gupta's
 message of "Wed, 12 Jun 2013 15:55:08 +0530")
References: <1371032708-9242-1-git-send-email-pekon@ti.com>
 <1371032708-9242-4-git-send-email-pekon@ti.com>
Message-ID: <8761xhbu51.fsf@linaro.org>

Pekon Gupta <pekon at ti.com> writes:

> From: avinash philip <avinashphilip at ti.com>
>
> In low power modes of AM335X platforms, peripherals power is cut off.
> This patch supports low power sleep transition support for ELM driver.

This series needs a bit more description about what "low power sleep
transition" is, and how adding runtime PM calls makes this transition
happen.

Kevin

> Signed-off-by: Philip Avinash <avinashphilip at ti.com>
> Signed-off-by: Pekon Gupta <pekon at ti.com>
> ---
>  drivers/mtd/devices/elm.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
>
> diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
> index dccef9f..171efcd 100644
> --- a/drivers/mtd/devices/elm.c
> +++ b/drivers/mtd/devices/elm.c
> @@ -20,6 +20,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/of.h>
> +#include <linux/sched.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/platform_data/elm.h>
>  
> @@ -385,6 +386,23 @@ static int elm_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int elm_suspend(struct device *dev)
> +{
> +	pm_runtime_put_sync(dev);
> +	return 0;
> +}
> +
> +static int elm_resume(struct device *dev)
> +{
> +	struct elm_info *info = dev_get_drvdata(dev);
> +
> +	pm_runtime_get_sync(dev);
> +	elm_config(dev, info->bch_type);
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
> +
>  #ifdef CONFIG_OF
>  static const struct of_device_id elm_of_match[] = {
>  	{ .compatible = "ti,am3352-elm" },
> @@ -398,6 +416,7 @@ static struct platform_driver elm_driver = {
>  		.name	= "elm",
>  		.owner	= THIS_MODULE,
>  		.of_match_table = of_match_ptr(elm_of_match),
> +		.pm	= &elm_pm_ops,
>  	},
>  	.probe	= elm_probe,
>  	.remove	= elm_remove,


From templer84 at kaonmedia.com  Thu Jun 13 22:18:42 2013
From: templer84 at kaonmedia.com (=?ks_c_5601-1987?B?vK2x4ryuW1NlbyBLaSBTZW9rXQ==?=)
Date: Fri, 14 Jun 2013 02:18:42 +0000
Subject: UBIFS io performance consistency issue
Message-ID: <d485c1a2c18a4c1daf05c6503767ca9f@HKNPR03MB019.apcprd03.prod.outlook.com>

Dear UBIFS developers

Kernel version : 2.6.37-2.8
Nand : Micron MT29F32G08CBACA (4GB, MLC)

Hi, I am using ubifs for 4GB MLC nandflash and basic working is well done.
But some issue torture me. I untar large file sometimes. But there are
wide variations in untar speed.
I spend 5~15 min(in sync mode) for 150MB file to untar. even spend 25
min for same file.
Why is this happening?
Of course I read ubi and ubifs documentations.
(http://www.linux-mtd.infradead.org/doc)
And I read "Does UBIFS become slower when it is full?"
(http://www.linux-mtd.infradead.org/faq/ubifs.html#L_slow_when_full)
But my nandflash is not close to full. I have 1.5GB more available capacity.
I wonder that ubifs io performance is consistency or not.
Please help me some tips for in this case. I need to be consistency
for io operations.
Thanks for reading my short English.

Respectfully yours
________________________________

The above message is intended solely for the named addressee and may contain trade secret and confidential information otherwise protected under applicable law.
Any unauthorized dissemination or use of the information contained in this communication is strictly prohibited.
If you have received this communication in error, please notify the sender by email and delete this communication immediately.

The Future of SmartTV and Connected Home... KaonMedia Co. Ltd. www.kaonmedia.com<http://www.kaonmedia.com>

From b32955 at freescale.com  Fri Jun 14 04:06:21 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Fri, 14 Jun 2013 16:06:21 +0800
Subject: [PATCH 0/4] mtd: gpmi: support two nand chips at most
Message-ID: <1371197185-27491-1-git-send-email-b32955@freescale.com>

Current gpmi-nand driver only supports one chips. But we may meet
some embarrassing situation, such as Micron MT29F32G08QAA.
This nand chip has two DIEs internally. Each die has its own chip select pin,
so this chip acts as two nand chips.

If we only scan one chip, we may find that we only get 2G for this chip,
but in actually, this chip's size is 4G.

So scan two chips by default.

In order to support two nand chips, we have to do the following:
   1.) We only have one dma channel now, so decouple the chip select
      from the DMA channel, We can use the dma 0 to access all the nand chips.

   2.) fix the wrong method of checking the ready/busy status.
      In the imx6, all the ready/busy pins are binding together, we
      should check ready/busy status of chip 0 for the all the chips. 

Tested this patch set with MT29F32G08QAA.


Huang Shijie (4):
  mtd: gpmi: decouple the chip select from the DMA channel
  mtd: gpmi: use DMA channel 0 for all the nand chips
  mtd: gpmi: scan two nand chips
  mtd: gpmi: imx6: fix the wrong method for checking ready/busy

 drivers/mtd/nand/gpmi-nand/gpmi-lib.c  |   14 ++++++++++++++
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c |    7 +++----
 drivers/mtd/nand/gpmi-nand/gpmi-regs.h |    3 +++
 3 files changed, 20 insertions(+), 4 deletions(-)




From b32955 at freescale.com  Fri Jun 14 04:06:23 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Fri, 14 Jun 2013 16:06:23 +0800
Subject: [PATCH 2/4] mtd: gpmi: use DMA channel 0 for all the nand chips
In-Reply-To: <1371197185-27491-1-git-send-email-b32955@freescale.com>
References: <1371197185-27491-1-git-send-email-b32955@freescale.com>
Message-ID: <1371197185-27491-3-git-send-email-b32955@freescale.com>

We only have one DMA channel : the channel 0.
Use DMA channel 0 to access all the nand chips.

Signed-off-by: Huang Shijie <b32955 at freescale.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 25ecfa1..036e5e4 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -226,9 +226,8 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
 
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
 {
-	int chipnr = this->current_chip;
-
-	return this->dma_chans[chipnr];
+	/* We use the DMA channel 0 to access all the nand chips. */
+	return this->dma_chans[0];
 }
 
 /* Can we use the upper's buffer directly for DMA? */
-- 
1.7.1




From b32955 at freescale.com  Fri Jun 14 04:06:24 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Fri, 14 Jun 2013 16:06:24 +0800
Subject: [PATCH 3/4] mtd: gpmi: scan two nand chips
In-Reply-To: <1371197185-27491-1-git-send-email-b32955@freescale.com>
References: <1371197185-27491-1-git-send-email-b32955@freescale.com>
Message-ID: <1371197185-27491-4-git-send-email-b32955@freescale.com>

Some nand chip has two DIEs in a single chip, such as Micron MT29F32G08QAA.
Each die has its own chip select pin, so this chip acts as two nand
chips.

If we only scan one chip, we may find that we only get 2G for this chip,
but in actually, this chip's size is 4G.

So scan two chips by default.

Signed-off-by: Huang Shijie <b32955 at freescale.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 036e5e4..bb8af93 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1551,7 +1551,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
 	if (ret)
 		goto err_out;
 
-	ret = nand_scan(mtd, 1);
+	ret = nand_scan(mtd, 2);
 	if (ret) {
 		pr_err("Chip scan failed\n");
 		goto err_out;
-- 
1.7.1




From b32955 at freescale.com  Fri Jun 14 04:06:22 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Fri, 14 Jun 2013 16:06:22 +0800
Subject: [PATCH 1/4] mtd: gpmi: decouple the chip select from the DMA channel
In-Reply-To: <1371197185-27491-1-git-send-email-b32955@freescale.com>
References: <1371197185-27491-1-git-send-email-b32955@freescale.com>
Message-ID: <1371197185-27491-2-git-send-email-b32955@freescale.com>

Decouple the chip select from the DMA channel, we use the DMA channel 0
to accecc all the nand devices.

Signed-off-by: Huang Shijie <b32955 at freescale.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-lib.c  |    6 ++++++
 drivers/mtd/nand/gpmi-nand/gpmi-regs.h |    3 +++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 4f8857f..7d56d87 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -187,6 +187,12 @@ int gpmi_init(struct gpmi_nand_data *this)
 	/* Select BCH ECC. */
 	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
 
+	/*
+	 * Decouple the chip select from dma channel. We use dma0 for all
+	 * the chips.
+	 */
+	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
 	gpmi_disable_clk(this);
 	return 0;
 err_out:
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
index 53397cc..82114cd 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
@@ -108,6 +108,9 @@
 #define HW_GPMI_CTRL1_CLR				0x00000068
 #define HW_GPMI_CTRL1_TOG				0x0000006c
 
+#define BP_GPMI_CTRL1_DECOUPLE_CS			24
+#define BM_GPMI_CTRL1_DECOUPLE_CS	(1 << BP_GPMI_CTRL1_DECOUPLE_CS)
+
 #define BP_GPMI_CTRL1_WRN_DLY_SEL			22
 #define BM_GPMI_CTRL1_WRN_DLY_SEL	(0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
 #define BF_GPMI_CTRL1_WRN_DLY_SEL(v)  \
-- 
1.7.1




From b32955 at freescale.com  Fri Jun 14 04:06:25 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Fri, 14 Jun 2013 16:06:25 +0800
Subject: [PATCH 4/4] mtd: gpmi: imx6: fix the wrong method for checking
 ready/busy
In-Reply-To: <1371197185-27491-1-git-send-email-b32955@freescale.com>
References: <1371197185-27491-1-git-send-email-b32955@freescale.com>
Message-ID: <1371197185-27491-5-git-send-email-b32955@freescale.com>

In the imx6, all the ready/busy pins are binding togeter.
So we only need to check the chip 0 busy status.

For example, When the CS1 is enabled, we also should check the
ready/busy of chip 0, if we check the ready/busy of chip 1,
we will get the wrong result.

Signed-off-by: Huang Shijie <b32955 at freescale.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-lib.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 7d56d87..660c5d7 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -1079,6 +1079,14 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
 		mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
 		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
 	} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) {
+		/*
+		 * In the imx6, all the ready/busy pins are binding
+		 * togeter. So we only need to check the ready/busy status
+		 * of chip 0.
+		 */
+		if (GPMI_IS_MX6Q(this))
+			chip = 0;
+
 		/* MX28 shares the same R/B register as MX6Q. */
 		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
 		reg = readl(r->gpmi_regs + HW_GPMI_STAT);
-- 
1.7.1




From sourav.poddar at ti.com  Fri Jun 14 10:33:09 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Fri, 14 Jun 2013 20:03:09 +0530
Subject: U-boot: Erase/read/write issue with S25fl256S flash device
In-Reply-To: <51B82388.2000909@ti.com>
References: <51B82388.2000909@ti.com>
Message-ID: <51BB29A5.3000100@ti.com>


Hi,

On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
> Hi,
>
> I am working on qspi flash device S25FL256S at u-boot level. I am 
> trying to
> make use of the existing spi_flash.c framework available at u-boot for 
> erasing/reading/writing
> into the flash device.
>
> There are several issues(mentioned below), which I faced while using 
> S25FL256s flash device
> with my dra7xx board which has a qspi controller to which the above 
> mentioned flash device is attached.
>
> 1. Erase (spi_flash_cmd_erase)
>
> Issuing a command something like this..
>
> sf erase 0x0 0x50000
>  - erases only first 0x20000 bytes of flash device, anything above 
> that is not erase. I need to
>    issue separate commands after 0x20000 for every 0x10000 bytes.
>
> Am i missing anything here?
>
> 2. read
>
> sf read 81000000 0 0x10000
>
> Read is not happening properly. The last few byte along the 4k 
> boundary always shows zero.
> Above 4k bytes, read is not happening.
>
> For ex:
>  DRA752 EVM # md 81000f00
> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>
> In this dump, if you see 81000ff0 the last column shows 000000 which is
> not expected. and it happens along every 4k bytes.
>
>
> So, to get rid of the above issue, I switched to page read with the 
> below patch[1],
> which is giving me the correct result.
> [1]:
> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash 
> *flash, const u8 *cmd,
>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>                 size_t len, void *data)
>  {
> -       u8 cmd[5];
> +       unsigned long page_addr, byte_addr, page_size;
> +       size_t chunk_len, actual;
> +       int ret = 0;
> +       u8 cmd[4];
>
>         /* Handle memory-mapped SPI */
>         if (flash->memory_map)
>                 memcpy(data, flash->memory_map + offset, len);
> +       page_size = flash->page_size;
> +       page_addr = offset / page_size;
> +       byte_addr = offset % page_size;
> +
> +       cmd[0] = CMD_READ_ARRAY_SLOW;
> +       for (actual = 0; actual < len; actual += chunk_len) {
> +               chunk_len = min(len - actual, page_size - byte_addr);
> +
> +               cmd[1] = page_addr >> 8;
> +               cmd[2] = page_addr;
> +               cmd[3] = byte_addr;
> +
> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd), 
> data + actual, chunk_len);
> +               if (ret < 0) {
> +                       debug("SF: read failed");
> +                       break;
> +               }
>
> -       cmd[0] = CMD_READ_ARRAY_FAST;
> -       spi_flash_addr(offset, cmd);
> -       cmd[4] = 0x00;
> +               byte_addr += chunk_len;
> +               if (byte_addr == page_size) {
> +                       page_addr++;
> +                       byte_addr = 0;
> +               }
> +       }
>
> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
> +       return ret;
>  }
>
> Any idea about this?
>
> 3.  write (spi_flash_cmd_write_multi)
>   write not happening properly.
>
> observations: only able to write single page, anything after a page is 
> not getting
>         written.
> Workaround:
> I did a write disable latch at the end of every write cycle(page 
> program) and enable it
> again for the next loop. With this, I see I get rid of the above issue.
>
>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash 
> *flash, u32 offset,
>                 if (ret)
>                         break;
>
> +               ret = spi_flash_cmd_write_disable(flash);
> +               if (ret < 0) {
> +                       printf("SF: disabling write failed\n");
> +                       break;
> +               }
> +
>
>
> Have anyone seen the above mentioned issues regarding 
> read/write/erase? OR is there any
> configurations that I might be missing ?
>
Any Input on this?



From jagannadh.teki at gmail.com  Fri Jun 14 10:38:28 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Fri, 14 Jun 2013 20:08:28 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BB29A5.3000100@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
Message-ID: <51BB2AE4.4020109@gmail.com>

On 14-06-2013 20:03, Sourav Poddar wrote:
>
> Hi,
>
> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>> Hi,
>>
>> I am working on qspi flash device S25FL256S at u-boot level. I am
>> trying to
>> make use of the existing spi_flash.c framework available at u-boot for
>> erasing/reading/writing
>> into the flash device.
>>
>> There are several issues(mentioned below), which I faced while using
>> S25FL256s flash device
>> with my dra7xx board which has a qspi controller to which the above
>> mentioned flash device is attached.
>>
>> 1. Erase (spi_flash_cmd_erase)
>>
>> Issuing a command something like this..
>>
>> sf erase 0x0 0x50000
>>  - erases only first 0x20000 bytes of flash device, anything above
>> that is not erase. I need to
>>    issue separate commands after 0x20000 for every 0x10000 bytes.
>>
>> Am i missing anything here?
>>
>> 2. read
>>
>> sf read 81000000 0 0x10000
>>
>> Read is not happening properly. The last few byte along the 4k
>> boundary always shows zero.
>> Above 4k bytes, read is not happening.
>>
>> For ex:
>>  DRA752 EVM # md 81000f00
>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>
>> In this dump, if you see 81000ff0 the last column shows 000000 which is
>> not expected. and it happens along every 4k bytes.
>>
>>
>> So, to get rid of the above issue, I switched to page read with the
>> below patch[1],
>> which is giving me the correct result.
>> [1]:
>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>> *flash, const u8 *cmd,
>>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>                 size_t len, void *data)
>>  {
>> -       u8 cmd[5];
>> +       unsigned long page_addr, byte_addr, page_size;
>> +       size_t chunk_len, actual;
>> +       int ret = 0;
>> +       u8 cmd[4];
>>
>>         /* Handle memory-mapped SPI */
>>         if (flash->memory_map)
>>                 memcpy(data, flash->memory_map + offset, len);
>> +       page_size = flash->page_size;
>> +       page_addr = offset / page_size;
>> +       byte_addr = offset % page_size;
>> +
>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>> +       for (actual = 0; actual < len; actual += chunk_len) {
>> +               chunk_len = min(len - actual, page_size - byte_addr);
>> +
>> +               cmd[1] = page_addr >> 8;
>> +               cmd[2] = page_addr;
>> +               cmd[3] = byte_addr;
>> +
>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>> data + actual, chunk_len);
>> +               if (ret < 0) {
>> +                       debug("SF: read failed");
>> +                       break;
>> +               }
>>
>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>> -       spi_flash_addr(offset, cmd);
>> -       cmd[4] = 0x00;
>> +               byte_addr += chunk_len;
>> +               if (byte_addr == page_size) {
>> +                       page_addr++;
>> +                       byte_addr = 0;
>> +               }
>> +       }
>>
>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
>> +       return ret;
>>  }
>>
>> Any idea about this?
>>
>> 3.  write (spi_flash_cmd_write_multi)
>>   write not happening properly.
>>
>> observations: only able to write single page, anything after a page is
>> not getting
>>         written.
>> Workaround:
>> I did a write disable latch at the end of every write cycle(page
>> program) and enable it
>> again for the next loop. With this, I see I get rid of the above issue.
>>
>>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>> *flash, u32 offset,
>>                 if (ret)
>>                         break;
>>
>> +               ret = spi_flash_cmd_write_disable(flash);
>> +               if (ret < 0) {
>> +                       printf("SF: disabling write failed\n");
>> +                       break;
>> +               }
>> +
>>
>>
>> Have anyone seen the above mentioned issues regarding
>> read/write/erase? OR is there any
>> configurations that I might be missing ?
>>
> Any Input on this?

Please wait, I am pushing some changes tonight or so.

We will continue this thread, after testing your part with these new 
changes.

I will intimate you once the push done.

--
Thanks,
Jagan.




From sourav.poddar at ti.com  Fri Jun 14 10:43:55 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Fri, 14 Jun 2013 20:13:55 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BB2AE4.4020109@gmail.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com>
Message-ID: <51BB2C2B.1010404@ti.com>

Hi Jagan,
On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
> On 14-06-2013 20:03, Sourav Poddar wrote:
>>
>> Hi,
>>
>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>> Hi,
>>>
>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>> trying to
>>> make use of the existing spi_flash.c framework available at u-boot for
>>> erasing/reading/writing
>>> into the flash device.
>>>
>>> There are several issues(mentioned below), which I faced while using
>>> S25FL256s flash device
>>> with my dra7xx board which has a qspi controller to which the above
>>> mentioned flash device is attached.
>>>
>>> 1. Erase (spi_flash_cmd_erase)
>>>
>>> Issuing a command something like this..
>>>
>>> sf erase 0x0 0x50000
>>>  - erases only first 0x20000 bytes of flash device, anything above
>>> that is not erase. I need to
>>>    issue separate commands after 0x20000 for every 0x10000 bytes.
>>>
>>> Am i missing anything here?
>>>
>>> 2. read
>>>
>>> sf read 81000000 0 0x10000
>>>
>>> Read is not happening properly. The last few byte along the 4k
>>> boundary always shows zero.
>>> Above 4k bytes, read is not happening.
>>>
>>> For ex:
>>>  DRA752 EVM # md 81000f00
>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>
>>> In this dump, if you see 81000ff0 the last column shows 000000 which is
>>> not expected. and it happens along every 4k bytes.
>>>
>>>
>>> So, to get rid of the above issue, I switched to page read with the
>>> below patch[1],
>>> which is giving me the correct result.
>>> [1]:
>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>> *flash, const u8 *cmd,
>>>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>                 size_t len, void *data)
>>>  {
>>> -       u8 cmd[5];
>>> +       unsigned long page_addr, byte_addr, page_size;
>>> +       size_t chunk_len, actual;
>>> +       int ret = 0;
>>> +       u8 cmd[4];
>>>
>>>         /* Handle memory-mapped SPI */
>>>         if (flash->memory_map)
>>>                 memcpy(data, flash->memory_map + offset, len);
>>> +       page_size = flash->page_size;
>>> +       page_addr = offset / page_size;
>>> +       byte_addr = offset % page_size;
>>> +
>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>> +       for (actual = 0; actual < len; actual += chunk_len) {
>>> +               chunk_len = min(len - actual, page_size - byte_addr);
>>> +
>>> +               cmd[1] = page_addr >> 8;
>>> +               cmd[2] = page_addr;
>>> +               cmd[3] = byte_addr;
>>> +
>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>> data + actual, chunk_len);
>>> +               if (ret < 0) {
>>> +                       debug("SF: read failed");
>>> +                       break;
>>> +               }
>>>
>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>> -       spi_flash_addr(offset, cmd);
>>> -       cmd[4] = 0x00;
>>> +               byte_addr += chunk_len;
>>> +               if (byte_addr == page_size) {
>>> +                       page_addr++;
>>> +                       byte_addr = 0;
>>> +               }
>>> +       }
>>>
>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data, 
>>> len);
>>> +       return ret;
>>>  }
>>>
>>> Any idea about this?
>>>
>>> 3.  write (spi_flash_cmd_write_multi)
>>>   write not happening properly.
>>>
>>> observations: only able to write single page, anything after a page is
>>> not getting
>>>         written.
>>> Workaround:
>>> I did a write disable latch at the end of every write cycle(page
>>> program) and enable it
>>> again for the next loop. With this, I see I get rid of the above issue.
>>>
>>>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>>> *flash, u32 offset,
>>>                 if (ret)
>>>                         break;
>>>
>>> +               ret = spi_flash_cmd_write_disable(flash);
>>> +               if (ret < 0) {
>>> +                       printf("SF: disabling write failed\n");
>>> +                       break;
>>> +               }
>>> +
>>>
>>>
>>> Have anyone seen the above mentioned issues regarding
>>> read/write/erase? OR is there any
>>> configurations that I might be missing ?
>>>
>> Any Input on this?
>
> Please wait, I am pushing some changes tonight or so.
>
> We will continue this thread, after testing your part with these new 
> changes.
>
> I will intimate you once the push done.
>
> -- 
> Thanks,
> Jagan.
>
>
Thanks a lot for the reply.
Sure, will wait for your changes to go in.

Thanks,
Sourav



From jagannadh.teki at gmail.com  Sat Jun 15 12:17:51 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Sat, 15 Jun 2013 21:47:51 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BB2C2B.1010404@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
Message-ID: <51BC93AF.5080808@gmail.com>

On 14-06-2013 20:13, Sourav Poddar wrote:
> Hi Jagan,
> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>
>>> Hi,
>>>
>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>> Hi,
>>>>
>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>> trying to
>>>> make use of the existing spi_flash.c framework available at u-boot for
>>>> erasing/reading/writing
>>>> into the flash device.
>>>>
>>>> There are several issues(mentioned below), which I faced while using
>>>> S25FL256s flash device
>>>> with my dra7xx board which has a qspi controller to which the above
>>>> mentioned flash device is attached.
>>>>
>>>> 1. Erase (spi_flash_cmd_erase)
>>>>
>>>> Issuing a command something like this..
>>>>
>>>> sf erase 0x0 0x50000
>>>>  - erases only first 0x20000 bytes of flash device, anything above
>>>> that is not erase. I need to
>>>>    issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>
>>>> Am i missing anything here?
>>>>
>>>> 2. read
>>>>
>>>> sf read 81000000 0 0x10000
>>>>
>>>> Read is not happening properly. The last few byte along the 4k
>>>> boundary always shows zero.
>>>> Above 4k bytes, read is not happening.
>>>>
>>>> For ex:
>>>>  DRA752 EVM # md 81000f00
>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>
>>>> In this dump, if you see 81000ff0 the last column shows 000000 which is
>>>> not expected. and it happens along every 4k bytes.
>>>>
>>>>
>>>> So, to get rid of the above issue, I switched to page read with the
>>>> below patch[1],
>>>> which is giving me the correct result.
>>>> [1]:
>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>> *flash, const u8 *cmd,
>>>>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>                 size_t len, void *data)
>>>>  {
>>>> -       u8 cmd[5];
>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>> +       size_t chunk_len, actual;
>>>> +       int ret = 0;
>>>> +       u8 cmd[4];
>>>>
>>>>         /* Handle memory-mapped SPI */
>>>>         if (flash->memory_map)
>>>>                 memcpy(data, flash->memory_map + offset, len);
>>>> +       page_size = flash->page_size;
>>>> +       page_addr = offset / page_size;
>>>> +       byte_addr = offset % page_size;
>>>> +
>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>> +       for (actual = 0; actual < len; actual += chunk_len) {
>>>> +               chunk_len = min(len - actual, page_size - byte_addr);
>>>> +
>>>> +               cmd[1] = page_addr >> 8;
>>>> +               cmd[2] = page_addr;
>>>> +               cmd[3] = byte_addr;
>>>> +
>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>> data + actual, chunk_len);
>>>> +               if (ret < 0) {
>>>> +                       debug("SF: read failed");
>>>> +                       break;
>>>> +               }
>>>>
>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>> -       spi_flash_addr(offset, cmd);
>>>> -       cmd[4] = 0x00;
>>>> +               byte_addr += chunk_len;
>>>> +               if (byte_addr == page_size) {
>>>> +                       page_addr++;
>>>> +                       byte_addr = 0;
>>>> +               }
>>>> +       }
>>>>
>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>> len);
>>>> +       return ret;
>>>>  }
>>>>
>>>> Any idea about this?
>>>>
>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>   write not happening properly.
>>>>
>>>> observations: only able to write single page, anything after a page is
>>>> not getting
>>>>         written.
>>>> Workaround:
>>>> I did a write disable latch at the end of every write cycle(page
>>>> program) and enable it
>>>> again for the next loop. With this, I see I get rid of the above issue.
>>>>
>>>>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>>>> *flash, u32 offset,
>>>>                 if (ret)
>>>>                         break;
>>>>
>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>> +               if (ret < 0) {
>>>> +                       printf("SF: disabling write failed\n");
>>>> +                       break;
>>>> +               }
>>>> +
>>>>
>>>>
>>>> Have anyone seen the above mentioned issues regarding
>>>> read/write/erase? OR is there any
>>>> configurations that I might be missing ?
>>>>
>>> Any Input on this?
>>
>> Please wait, I am pushing some changes tonight or so.
>>
>> We will continue this thread, after testing your part with these new
>> changes.
>>
>> I will intimate you once the push done.
>>
>> --
>> Thanks,
>> Jagan.
>>
>>
> Thanks a lot for the reply.
> Sure, will wait for your changes to go in.

Will take some time go these changes on master.

Please checkout master-work branch in u-boot-spi repo
git://git.denx.de/u-boot-spi.git

and try to test 256S parts, fyi: I tested the same part got the
+ve result.

--
Thanks,
Jagan.


From Mats.Karrman at tritech.se  Sat Jun 15 18:25:32 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Sat, 15 Jun 2013 22:25:32 +0000
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3C5D@SI-MBX14.de.bosch.com>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD57@post.tritech.se>

Those patches are not in my source.
// Mats

________________________________________
From: Prins Anton (ST-CO/ENG1.1) [Anton.Prins at nl.bosch.com]
Sent: Thursday, June 13, 2013 3:31 PM
To: Mats K?rrman; Adrian Hunter
Cc: linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: RE: UBIFS failure & stable page writes

We decided not to patch for this weekend, but onlty make an additional logging in UBIFS:

diff -purN a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
--- a/fs/ubifs/orphan.c 2013-06-13 12:19:58.490931170 +0200
+++ b/fs/ubifs/orphan.c 2013-06-13 12:17:13.014931462 +0200
@@ -300,6 +300,9 @@ static int write_orph_node(struct ubifs_
        for (i = 0; i < cnt; i++) {
                orphan = cnext;
                orph->inos[i] = cpu_to_le64(orphan->inum);
+               if (orph->inos[i] < UBIFS_FIRST_INO) {
+                       printk(KERN_ERR "ERROR: Wrong ino in orphan list[%lu]: %lu\n", (unsigned long)i, (unsigned long)orph->inos[i]);
+               }
                cnext = orphan->cnext;
                orphan->cnext = NULL;
        }

This to make sure if UBIFS itself writes a node '0' or '1'... and it is forced by UBI, NAND, Peripheral or NAND-Device.
If there is a relation between logging and failing after reboot it would make sense... Means a lot of analyzing; but we have to find it!

Next step is to apply patches and to test again:
http://git.infradead.org/ubifs-2.6.git/commit/8afd500cb52a5d00bab4525dd5a560d199f979b9
http://git.infradead.org/ubifs-2.6.git/commit/2928f0d0c5ebd6c9605c0d98207a44376387c298

And hopefully we get rid of some unexpected orphan nodes.

How realistic is it that the double orphan free causes our problem?
Mats, are you sure the patches mentioned above are also not in your UBIFS?



From Mats.Karrman at tritech.se  Sat Jun 15 18:45:51 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Sat, 15 Jun 2013 22:45:51 +0000
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>

Hi Anton,

1. Yes, there are files added, removed and renamed.
2. Single core, 32-bit PowerPC e300c4 in BE mode, CONFIG_PREEMPT=y.
3. Never tried a graceful one ;) Normal procedure is shutting down application + sync + power off to be as quick as possible. However, as other people are responsible for those units that experienced this problem I can't be sure that no-one used the shutdown command but it's unlikely.

BR // Mats
________________________________________
From: Prins Anton (ST-CO/ENG1.1) [Anton.Prins at nl.bosch.com]
Sent: Thursday, June 13, 2013 9:24 PM
To: Mats K?rrman; Adrian Hunter
Cc: linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: RE: UBIFS failure & stable page writes

Hi Mats,

Some questions to get more feeling with our problem:

1. Does your application add/remove files (delete/unlink?)
2. Does your kernel run on a single or multi-core machine?
3. Do you experience it with an ungraceful shutdown or also graceful?

The statistics we see is that rebooting every 5 minutes will not give higher occurrence.
It seems that device turned on for a longer time have more chance to fail; but as said not predictable.



From grinberg at compulab.co.il  Mon Jun 17 01:53:25 2013
From: grinberg at compulab.co.il (Igor Grinberg)
Date: Mon, 17 Jun 2013 08:53:25 +0300
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
Message-ID: <51BEA455.2020605@compulab.co.il>

Hi Ezequiel,

On 05/14/13 14:15, Ezequiel Garcia wrote:
> The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
> is similar to the one in PXA SoC. Therefore, it should be possible to support
> Armada NAND using pxa3xx-nand driver.
> 
> While this effort is not ready yet, here is a set of patches that are needed
> for such work.
> 
> A small summary of the patches:
> 
>   * 1/5 is a fix for a 2-year regression that removed DMA support.
> 
>   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
> 
>   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
>     to successfully probe newer flash devices.
> 
> Applies cleanly on top of l2-mtd.git.
> 
> Thanks!
> 
> Ezequiel Garcia (5):
>   mtd: nand: pxa3xx: Set info->use_dma properly
>   mtd: nand: pxa3xx: Use of_machine_is_compatible()
>   mtd: nand: pxa3xx: Fix MODULE_DEVICE_TABLE declaration
>   mtd: nand: pxa3xx: Add address support for READID command
>   mtd: nand: pxa3xx: Add support for Read parameter page command

tested on cm-x300, upstream 3.10-rc5 and no regressions seen.

Tested-by: Nikita Kiryanov <nikita at compulab.co.il>
Acked-by: Igor Grinberg <grinberg at compulab.co.il>

> 
>  drivers/mtd/nand/pxa3xx_nand.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 

-- 
Regards,
Igor.


From sourav.poddar at ti.com  Mon Jun 17 02:14:45 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 11:44:45 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BC93AF.5080808@gmail.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com>
Message-ID: <51BEA955.9080907@ti.com>

Hi Jagan,
On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
> On 14-06-2013 20:13, Sourav Poddar wrote:
>> Hi Jagan,
>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>
>>>> Hi,
>>>>
>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>> Hi,
>>>>>
>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>> trying to
>>>>> make use of the existing spi_flash.c framework available at u-boot 
>>>>> for
>>>>> erasing/reading/writing
>>>>> into the flash device.
>>>>>
>>>>> There are several issues(mentioned below), which I faced while using
>>>>> S25FL256s flash device
>>>>> with my dra7xx board which has a qspi controller to which the above
>>>>> mentioned flash device is attached.
>>>>>
>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>
>>>>> Issuing a command something like this..
>>>>>
>>>>> sf erase 0x0 0x50000
>>>>>  - erases only first 0x20000 bytes of flash device, anything above
>>>>> that is not erase. I need to
>>>>>    issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>>
>>>>> Am i missing anything here?
>>>>>
>>>>> 2. read
>>>>>
>>>>> sf read 81000000 0 0x10000
>>>>>
>>>>> Read is not happening properly. The last few byte along the 4k
>>>>> boundary always shows zero.
>>>>> Above 4k bytes, read is not happening.
>>>>>
>>>>> For ex:
>>>>>  DRA752 EVM # md 81000f00
>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>
>>>>> In this dump, if you see 81000ff0 the last column shows 000000 
>>>>> which is
>>>>> not expected. and it happens along every 4k bytes.
>>>>>
>>>>>
>>>>> So, to get rid of the above issue, I switched to page read with the
>>>>> below patch[1],
>>>>> which is giving me the correct result.
>>>>> [1]:
>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>> *flash, const u8 *cmd,
>>>>>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>>                 size_t len, void *data)
>>>>>  {
>>>>> -       u8 cmd[5];
>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>> +       size_t chunk_len, actual;
>>>>> +       int ret = 0;
>>>>> +       u8 cmd[4];
>>>>>
>>>>>         /* Handle memory-mapped SPI */
>>>>>         if (flash->memory_map)
>>>>>                 memcpy(data, flash->memory_map + offset, len);
>>>>> +       page_size = flash->page_size;
>>>>> +       page_addr = offset / page_size;
>>>>> +       byte_addr = offset % page_size;
>>>>> +
>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>> +       for (actual = 0; actual < len; actual += chunk_len) {
>>>>> +               chunk_len = min(len - actual, page_size - byte_addr);
>>>>> +
>>>>> +               cmd[1] = page_addr >> 8;
>>>>> +               cmd[2] = page_addr;
>>>>> +               cmd[3] = byte_addr;
>>>>> +
>>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>> data + actual, chunk_len);
>>>>> +               if (ret < 0) {
>>>>> +                       debug("SF: read failed");
>>>>> +                       break;
>>>>> +               }
>>>>>
>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>> -       spi_flash_addr(offset, cmd);
>>>>> -       cmd[4] = 0x00;
>>>>> +               byte_addr += chunk_len;
>>>>> +               if (byte_addr == page_size) {
>>>>> +                       page_addr++;
>>>>> +                       byte_addr = 0;
>>>>> +               }
>>>>> +       }
>>>>>
>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>>> len);
>>>>> +       return ret;
>>>>>  }
>>>>>
>>>>> Any idea about this?
>>>>>
>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>   write not happening properly.
>>>>>
>>>>> observations: only able to write single page, anything after a 
>>>>> page is
>>>>> not getting
>>>>>         written.
>>>>> Workaround:
>>>>> I did a write disable latch at the end of every write cycle(page
>>>>> program) and enable it
>>>>> again for the next loop. With this, I see I get rid of the above 
>>>>> issue.
>>>>>
>>>>>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>>>>> *flash, u32 offset,
>>>>>                 if (ret)
>>>>>                         break;
>>>>>
>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>> +               if (ret < 0) {
>>>>> +                       printf("SF: disabling write failed\n");
>>>>> +                       break;
>>>>> +               }
>>>>> +
>>>>>
>>>>>
>>>>> Have anyone seen the above mentioned issues regarding
>>>>> read/write/erase? OR is there any
>>>>> configurations that I might be missing ?
>>>>>
>>>> Any Input on this?
>>>
>>> Please wait, I am pushing some changes tonight or so.
>>>
>>> We will continue this thread, after testing your part with these new
>>> changes.
>>>
>>> I will intimate you once the push done.
>>>
>>> -- 
>>> Thanks,
>>> Jagan.
>>>
>>>
>> Thanks a lot for the reply.
>> Sure, will wait for your changes to go in.
>
> Will take some time go these changes on master.
>
> Please checkout master-work branch in u-boot-spi repo
> git://git.denx.de/u-boot-spi.git
>
> and try to test 256S parts, fyi: I tested the same part got the
> +ve result.
>
Tested the above tree on my board.
But, still the issues remain the same for me in all the three
cases(erase/read/write).

Here is the short log of the read command..
DRA752 EVM # sf probe 0
SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
SF: Warning - Only lower 16MiB accessible, Full access #define 
CONFIG_SPI_FLASH_BAR
DRA752 EVM # sf erase 0x0 0x10000
SF: 65536 bytes @ 0x0 Erased: OK
DRA752 EVM # mw.b 0x81000100 0xff 0x10000
DRA752 EVM # sf read 0x81003000 0x0 0x10000
SF: 65536 bytes @ 0x0 Read: OK
DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
Total of 4091 byte(s) were the same


Erase: not able to do with a single command, need to issue for every 
0x10000 bytes.

Write: Need to disable latch after every write to make it properly work.

Is it possible for you to  give me  basic commands which you might have 
ran to confirm
the read/write and erase ??


Thanks,
Sourav

> -- 
> Thanks,
> Jagan.



From jagannadh.teki at gmail.com  Mon Jun 17 02:47:57 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 12:17:57 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BEA955.9080907@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
Message-ID: <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>

Hi Sourav,

On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> Hi Jagan,
>
> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>
>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>
>>> Hi Jagan,
>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>
>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>> trying to
>>>>>> make use of the existing spi_flash.c framework available at u-boot for
>>>>>> erasing/reading/writing
>>>>>> into the flash device.
>>>>>>
>>>>>> There are several issues(mentioned below), which I faced while using
>>>>>> S25FL256s flash device
>>>>>> with my dra7xx board which has a qspi controller to which the above
>>>>>> mentioned flash device is attached.
>>>>>>
>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>
>>>>>> Issuing a command something like this..
>>>>>>
>>>>>> sf erase 0x0 0x50000
>>>>>>  - erases only first 0x20000 bytes of flash device, anything above
>>>>>> that is not erase. I need to
>>>>>>    issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>>>
>>>>>> Am i missing anything here?
>>>>>>
>>>>>> 2. read
>>>>>>
>>>>>> sf read 81000000 0 0x10000
>>>>>>
>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>> boundary always shows zero.
>>>>>> Above 4k bytes, read is not happening.
>>>>>>
>>>>>> For ex:
>>>>>>  DRA752 EVM # md 81000f00
>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>
>>>>>> In this dump, if you see 81000ff0 the last column shows 000000 which
>>>>>> is
>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>
>>>>>>
>>>>>> So, to get rid of the above issue, I switched to page read with the
>>>>>> below patch[1],
>>>>>> which is giving me the correct result.
>>>>>> [1]:
>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>> *flash, const u8 *cmd,
>>>>>>  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>>>                 size_t len, void *data)
>>>>>>  {
>>>>>> -       u8 cmd[5];
>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>> +       size_t chunk_len, actual;
>>>>>> +       int ret = 0;
>>>>>> +       u8 cmd[4];
>>>>>>
>>>>>>         /* Handle memory-mapped SPI */
>>>>>>         if (flash->memory_map)
>>>>>>                 memcpy(data, flash->memory_map + offset, len);
>>>>>> +       page_size = flash->page_size;
>>>>>> +       page_addr = offset / page_size;
>>>>>> +       byte_addr = offset % page_size;
>>>>>> +
>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>> +       for (actual = 0; actual < len; actual += chunk_len) {
>>>>>> +               chunk_len = min(len - actual, page_size - byte_addr);
>>>>>> +
>>>>>> +               cmd[1] = page_addr >> 8;
>>>>>> +               cmd[2] = page_addr;
>>>>>> +               cmd[3] = byte_addr;
>>>>>> +
>>>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>> data + actual, chunk_len);
>>>>>> +               if (ret < 0) {
>>>>>> +                       debug("SF: read failed");
>>>>>> +                       break;
>>>>>> +               }
>>>>>>
>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>> -       cmd[4] = 0x00;
>>>>>> +               byte_addr += chunk_len;
>>>>>> +               if (byte_addr == page_size) {
>>>>>> +                       page_addr++;
>>>>>> +                       byte_addr = 0;
>>>>>> +               }
>>>>>> +       }
>>>>>>
>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>>>> len);
>>>>>> +       return ret;
>>>>>>  }
>>>>>>
>>>>>> Any idea about this?
>>>>>>
>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>   write not happening properly.
>>>>>>
>>>>>> observations: only able to write single page, anything after a page is
>>>>>> not getting
>>>>>>         written.
>>>>>> Workaround:
>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>> program) and enable it
>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>> issue.
>>>>>>
>>>>>>  @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>>>>>> *flash, u32 offset,
>>>>>>                 if (ret)
>>>>>>                         break;
>>>>>>
>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>> +               if (ret < 0) {
>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>> +                       break;
>>>>>> +               }
>>>>>> +
>>>>>>
>>>>>>
>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>> read/write/erase? OR is there any
>>>>>> configurations that I might be missing ?
>>>>>>
>>>>> Any Input on this?
>>>>
>>>>
>>>> Please wait, I am pushing some changes tonight or so.
>>>>
>>>> We will continue this thread, after testing your part with these new
>>>> changes.
>>>>
>>>> I will intimate you once the push done.
>>>>
>>>> --
>>>> Thanks,
>>>> Jagan.
>>>>
>>>>
>>> Thanks a lot for the reply.
>>> Sure, will wait for your changes to go in.
>>
>>
>> Will take some time go these changes on master.
>>
>> Please checkout master-work branch in u-boot-spi repo
>> git://git.denx.de/u-boot-spi.git
>>
>> and try to test 256S parts, fyi: I tested the same part got the
>> +ve result.
>>
> Tested the above tree on my board.
> But, still the issues remain the same for me in all the three
> cases(erase/read/write).
>
> Here is the short log of the read command..
> DRA752 EVM # sf probe 0
> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
> SF: Warning - Only lower 16MiB accessible, Full access #define
> CONFIG_SPI_FLASH_BAR
> DRA752 EVM # sf erase 0x0 0x10000
> SF: 65536 bytes @ 0x0 Erased: OK
> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
> DRA752 EVM # sf read 0x81003000 0x0 0x10000
> SF: 65536 bytes @ 0x0 Read: OK
> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
> Total of 4091 byte(s) were the same
>
>
> Erase: not able to do with a single command, need to issue for every 0x10000
> bytes.
>
> Write: Need to disable latch after every write to make it properly work.
>
> Is it possible for you to  give me  basic commands which you might have ran
> to confirm
> the read/write and erase ??

I tested the same part - for me i couldn't see the issues with SL256S

OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
make debug -> printf.
Do the same test.! and send the log file.

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 02:58:51 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 12:28:51 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
Message-ID: <51BEB3AB.6020603@ti.com>

HI Jagan,
On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
> Hi Sourav,
>
> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> Hi Jagan,
>>
>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>> Hi Jagan,
>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>>> trying to
>>>>>>> make use of the existing spi_flash.c framework available at u-boot for
>>>>>>> erasing/reading/writing
>>>>>>> into the flash device.
>>>>>>>
>>>>>>> There are several issues(mentioned below), which I faced while using
>>>>>>> S25FL256s flash device
>>>>>>> with my dra7xx board which has a qspi controller to which the above
>>>>>>> mentioned flash device is attached.
>>>>>>>
>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>
>>>>>>> Issuing a command something like this..
>>>>>>>
>>>>>>> sf erase 0x0 0x50000
>>>>>>>   - erases only first 0x20000 bytes of flash device, anything above
>>>>>>> that is not erase. I need to
>>>>>>>     issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>>>>
>>>>>>> Am i missing anything here?
>>>>>>>
>>>>>>> 2. read
>>>>>>>
>>>>>>> sf read 81000000 0 0x10000
>>>>>>>
>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>> boundary always shows zero.
>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>
>>>>>>> For ex:
>>>>>>>   DRA752 EVM # md 81000f00
>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>>
>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000 which
>>>>>>> is
>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>
>>>>>>>
>>>>>>> So, to get rid of the above issue, I switched to page read with the
>>>>>>> below patch[1],
>>>>>>> which is giving me the correct result.
>>>>>>> [1]:
>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>> *flash, const u8 *cmd,
>>>>>>>   int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>>>>                  size_t len, void *data)
>>>>>>>   {
>>>>>>> -       u8 cmd[5];
>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>> +       size_t chunk_len, actual;
>>>>>>> +       int ret = 0;
>>>>>>> +       u8 cmd[4];
>>>>>>>
>>>>>>>          /* Handle memory-mapped SPI */
>>>>>>>          if (flash->memory_map)
>>>>>>>                  memcpy(data, flash->memory_map + offset, len);
>>>>>>> +       page_size = flash->page_size;
>>>>>>> +       page_addr = offset / page_size;
>>>>>>> +       byte_addr = offset % page_size;
>>>>>>> +
>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>> +       for (actual = 0; actual<  len; actual += chunk_len) {
>>>>>>> +               chunk_len = min(len - actual, page_size - byte_addr);
>>>>>>> +
>>>>>>> +               cmd[1] = page_addr>>  8;
>>>>>>> +               cmd[2] = page_addr;
>>>>>>> +               cmd[3] = byte_addr;
>>>>>>> +
>>>>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>> data + actual, chunk_len);
>>>>>>> +               if (ret<  0) {
>>>>>>> +                       debug("SF: read failed");
>>>>>>> +                       break;
>>>>>>> +               }
>>>>>>>
>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>> -       cmd[4] = 0x00;
>>>>>>> +               byte_addr += chunk_len;
>>>>>>> +               if (byte_addr == page_size) {
>>>>>>> +                       page_addr++;
>>>>>>> +                       byte_addr = 0;
>>>>>>> +               }
>>>>>>> +       }
>>>>>>>
>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>>>>> len);
>>>>>>> +       return ret;
>>>>>>>   }
>>>>>>>
>>>>>>> Any idea about this?
>>>>>>>
>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>    write not happening properly.
>>>>>>>
>>>>>>> observations: only able to write single page, anything after a page is
>>>>>>> not getting
>>>>>>>          written.
>>>>>>> Workaround:
>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>> program) and enable it
>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>> issue.
>>>>>>>
>>>>>>>   @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct spi_flash
>>>>>>> *flash, u32 offset,
>>>>>>>                  if (ret)
>>>>>>>                          break;
>>>>>>>
>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>> +               if (ret<  0) {
>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>> +                       break;
>>>>>>> +               }
>>>>>>> +
>>>>>>>
>>>>>>>
>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>> read/write/erase? OR is there any
>>>>>>> configurations that I might be missing ?
>>>>>>>
>>>>>> Any Input on this?
>>>>>
>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>
>>>>> We will continue this thread, after testing your part with these new
>>>>> changes.
>>>>>
>>>>> I will intimate you once the push done.
>>>>>
>>>>> --
>>>>> Thanks,
>>>>> Jagan.
>>>>>
>>>>>
>>>> Thanks a lot for the reply.
>>>> Sure, will wait for your changes to go in.
>>>
>>> Will take some time go these changes on master.
>>>
>>> Please checkout master-work branch in u-boot-spi repo
>>> git://git.denx.de/u-boot-spi.git
>>>
>>> and try to test 256S parts, fyi: I tested the same part got the
>>> +ve result.
>>>
>> Tested the above tree on my board.
>> But, still the issues remain the same for me in all the three
>> cases(erase/read/write).
>>
>> Here is the short log of the read command..
>> DRA752 EVM # sf probe 0
>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>> SF: Warning - Only lower 16MiB accessible, Full access #define
>> CONFIG_SPI_FLASH_BAR
>> DRA752 EVM # sf erase 0x0 0x10000
>> SF: 65536 bytes @ 0x0 Erased: OK
>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>> SF: 65536 bytes @ 0x0 Read: OK
>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>> Total of 4091 byte(s) were the same
>>
>>
>> Erase: not able to do with a single command, need to issue for every 0x10000
>> bytes.
>>
>> Write: Need to disable latch after every write to make it properly work.
>>
>> Is it possible for you to  give me  basic commands which you might have ran
>> to confirm
>> the read/write and erase ??
> I tested the same part - for me i couldn't see the issues with SL256S
>
> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
> make debug ->  printf.
> Do the same test.! and send the log file.
>
> --
> Thanks,
> Jagan.
Here is the output log, no change..

DRA752 EVM # sf probe 0
SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
DRA752 EVM # sf erase 0x0 0x10000
SF: 65536 bytes @ 0x0 Erased: OK
DRA752 EVM # mw.b 0x81000100 0xff 0x10000
DRA752 EVM # sf read 0x81003000 0x0 0x10000
SF: 65536 bytes @ 0x0 Read: OK
DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
Total of 4091 byte(s) were the same
DRA752 EVM #


Code change: for above output.
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, 
unsigned long timeout)

         ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
         if (ret) {
-               debug("SF: fail to read %s status register\n",
+               printf("SF: fail to read %s status register\n",
                         cmd == CMD_READ_STATUS ? "read" : "flag");
                 return ret;
         }
@@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash 
*flash, unsigned long timeout)
                 return 0;

         /* Timed out */
-       debug("SF: time out!\n");
+       printf("SF: time out!\n");
         return -1;
  }



~Sourav



From jagannadh.teki at gmail.com  Mon Jun 17 03:05:48 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 12:35:48 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BEB3AB.6020603@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
 <51BEB3AB.6020603@ti.com>
Message-ID: <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>

On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> HI Jagan,
>
> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>
>> Hi Sourav,
>>
>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>> wrote:
>>>
>>> Hi Jagan,
>>>
>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>
>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>
>>>>> Hi Jagan,
>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>
>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>>>> trying to
>>>>>>>> make use of the existing spi_flash.c framework available at u-boot
>>>>>>>> for
>>>>>>>> erasing/reading/writing
>>>>>>>> into the flash device.
>>>>>>>>
>>>>>>>> There are several issues(mentioned below), which I faced while using
>>>>>>>> S25FL256s flash device
>>>>>>>> with my dra7xx board which has a qspi controller to which the above
>>>>>>>> mentioned flash device is attached.
>>>>>>>>
>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>
>>>>>>>> Issuing a command something like this..
>>>>>>>>
>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>   - erases only first 0x20000 bytes of flash device, anything above
>>>>>>>> that is not erase. I need to
>>>>>>>>     issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>>>>>
>>>>>>>> Am i missing anything here?
>>>>>>>>
>>>>>>>> 2. read
>>>>>>>>
>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>
>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>> boundary always shows zero.
>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>
>>>>>>>> For ex:
>>>>>>>>   DRA752 EVM # md 81000f00
>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>>>
>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000 which
>>>>>>>> is
>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>
>>>>>>>>
>>>>>>>> So, to get rid of the above issue, I switched to page read with the
>>>>>>>> below patch[1],
>>>>>>>> which is giving me the correct result.
>>>>>>>> [1]:
>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>   int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>>>>>                  size_t len, void *data)
>>>>>>>>   {
>>>>>>>> -       u8 cmd[5];
>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>> +       int ret = 0;
>>>>>>>> +       u8 cmd[4];
>>>>>>>>
>>>>>>>>          /* Handle memory-mapped SPI */
>>>>>>>>          if (flash->memory_map)
>>>>>>>>                  memcpy(data, flash->memory_map + offset, len);
>>>>>>>> +       page_size = flash->page_size;
>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>> +
>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>> +       for (actual = 0; actual<  len; actual += chunk_len) {
>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>> byte_addr);
>>>>>>>> +
>>>>>>>> +               cmd[1] = page_addr>>  8;
>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>> +
>>>>>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>> data + actual, chunk_len);
>>>>>>>> +               if (ret<  0) {
>>>>>>>> +                       debug("SF: read failed");
>>>>>>>> +                       break;
>>>>>>>> +               }
>>>>>>>>
>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>> +                       page_addr++;
>>>>>>>> +                       byte_addr = 0;
>>>>>>>> +               }
>>>>>>>> +       }
>>>>>>>>
>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>>>>>> len);
>>>>>>>> +       return ret;
>>>>>>>>   }
>>>>>>>>
>>>>>>>> Any idea about this?
>>>>>>>>
>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>    write not happening properly.
>>>>>>>>
>>>>>>>> observations: only able to write single page, anything after a page
>>>>>>>> is
>>>>>>>> not getting
>>>>>>>>          written.
>>>>>>>> Workaround:
>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>> program) and enable it
>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>> issue.
>>>>>>>>
>>>>>>>>   @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>> spi_flash
>>>>>>>> *flash, u32 offset,
>>>>>>>>                  if (ret)
>>>>>>>>                          break;
>>>>>>>>
>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>> +               if (ret<  0) {
>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>> +                       break;
>>>>>>>> +               }
>>>>>>>> +
>>>>>>>>
>>>>>>>>
>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>> read/write/erase? OR is there any
>>>>>>>> configurations that I might be missing ?
>>>>>>>>
>>>>>>> Any Input on this?
>>>>>>
>>>>>>
>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>
>>>>>> We will continue this thread, after testing your part with these new
>>>>>> changes.
>>>>>>
>>>>>> I will intimate you once the push done.
>>>>>>
>>>>>> --
>>>>>> Thanks,
>>>>>> Jagan.
>>>>>>
>>>>>>
>>>>> Thanks a lot for the reply.
>>>>> Sure, will wait for your changes to go in.
>>>>
>>>>
>>>> Will take some time go these changes on master.
>>>>
>>>> Please checkout master-work branch in u-boot-spi repo
>>>> git://git.denx.de/u-boot-spi.git
>>>>
>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>> +ve result.
>>>>
>>> Tested the above tree on my board.
>>> But, still the issues remain the same for me in all the three
>>> cases(erase/read/write).
>>>
>>> Here is the short log of the read command..
>>> DRA752 EVM # sf probe 0
>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>> CONFIG_SPI_FLASH_BAR
>>> DRA752 EVM # sf erase 0x0 0x10000
>>> SF: 65536 bytes @ 0x0 Erased: OK
>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>> SF: 65536 bytes @ 0x0 Read: OK
>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>> Total of 4091 byte(s) were the same
>>>
>>>
>>> Erase: not able to do with a single command, need to issue for every
>>> 0x10000
>>> bytes.
>>>
>>> Write: Need to disable latch after every write to make it properly work.
>>>
>>> Is it possible for you to  give me  basic commands which you might have
>>> ran
>>> to confirm
>>> the read/write and erase ??
>>
>> I tested the same part - for me i couldn't see the issues with SL256S
>>
>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>> make debug ->  printf.
>> Do the same test.! and send the log file.
>>
>> --
>> Thanks,
>> Jagan.
>
> Here is the output log, no change..
>
>
> DRA752 EVM # sf probe 0
> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
> DRA752 EVM # sf erase 0x0 0x10000
> SF: 65536 bytes @ 0x0 Erased: OK
> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
> DRA752 EVM # sf read 0x81003000 0x0 0x10000
> SF: 65536 bytes @ 0x0 Read: OK
> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
> Total of 4091 byte(s) were the same
> DRA752 EVM #
>
>
> Code change: for above output.
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
> unsigned long timeout)
>
>         ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
>         if (ret) {
> -               debug("SF: fail to read %s status register\n",
> +               printf("SF: fail to read %s status register\n",
>                         cmd == CMD_READ_STATUS ? "read" : "flag");
>                 return ret;
>         }
> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
> unsigned long timeout)
>                 return 0;
>
>         /* Timed out */
> -       debug("SF: time out!\n");
> +       printf("SF: time out!\n");
>         return -1;
>  }
>

Ohh..

- What if you erase the entire flash and read back, same result is it?
- please send the paths for config file for this board?

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 03:11:23 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 12:41:23 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>	<CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>	<51BEB3AB.6020603@ti.com>
 <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
Message-ID: <51BEB69B.5010902@ti.com>

On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> HI Jagan,
>>
>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>> Hi Sourav,
>>>
>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>>> wrote:
>>>> Hi Jagan,
>>>>
>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>> Hi Jagan,
>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>>>>> trying to
>>>>>>>>> make use of the existing spi_flash.c framework available at u-boot
>>>>>>>>> for
>>>>>>>>> erasing/reading/writing
>>>>>>>>> into the flash device.
>>>>>>>>>
>>>>>>>>> There are several issues(mentioned below), which I faced while using
>>>>>>>>> S25FL256s flash device
>>>>>>>>> with my dra7xx board which has a qspi controller to which the above
>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>
>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>
>>>>>>>>> Issuing a command something like this..
>>>>>>>>>
>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>    - erases only first 0x20000 bytes of flash device, anything above
>>>>>>>>> that is not erase. I need to
>>>>>>>>>      issue separate commands after 0x20000 for every 0x10000 bytes.
>>>>>>>>>
>>>>>>>>> Am i missing anything here?
>>>>>>>>>
>>>>>>>>> 2. read
>>>>>>>>>
>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>
>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>> boundary always shows zero.
>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>
>>>>>>>>> For ex:
>>>>>>>>>    DRA752 EVM # md 81000f00
>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>>>>
>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000 which
>>>>>>>>> is
>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> So, to get rid of the above issue, I switched to page read with the
>>>>>>>>> below patch[1],
>>>>>>>>> which is giving me the correct result.
>>>>>>>>> [1]:
>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>    int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
>>>>>>>>>                   size_t len, void *data)
>>>>>>>>>    {
>>>>>>>>> -       u8 cmd[5];
>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>> +       int ret = 0;
>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>
>>>>>>>>>           /* Handle memory-mapped SPI */
>>>>>>>>>           if (flash->memory_map)
>>>>>>>>>                   memcpy(data, flash->memory_map + offset, len);
>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>> +
>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>> +       for (actual = 0; actual<   len; actual += chunk_len) {
>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>> byte_addr);
>>>>>>>>> +
>>>>>>>>> +               cmd[1] = page_addr>>   8;
>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>> +
>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>> data + actual, chunk_len);
>>>>>>>>> +               if (ret<   0) {
>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>> +                       break;
>>>>>>>>> +               }
>>>>>>>>>
>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>> +                       page_addr++;
>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>> +               }
>>>>>>>>> +       }
>>>>>>>>>
>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd), data,
>>>>>>>>> len);
>>>>>>>>> +       return ret;
>>>>>>>>>    }
>>>>>>>>>
>>>>>>>>> Any idea about this?
>>>>>>>>>
>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>     write not happening properly.
>>>>>>>>>
>>>>>>>>> observations: only able to write single page, anything after a page
>>>>>>>>> is
>>>>>>>>> not getting
>>>>>>>>>           written.
>>>>>>>>> Workaround:
>>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>>> program) and enable it
>>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>>> issue.
>>>>>>>>>
>>>>>>>>>    @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>> spi_flash
>>>>>>>>> *flash, u32 offset,
>>>>>>>>>                   if (ret)
>>>>>>>>>                           break;
>>>>>>>>>
>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>> +               if (ret<   0) {
>>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>>> +                       break;
>>>>>>>>> +               }
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>
>>>>>>>> Any Input on this?
>>>>>>>
>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>
>>>>>>> We will continue this thread, after testing your part with these new
>>>>>>> changes.
>>>>>>>
>>>>>>> I will intimate you once the push done.
>>>>>>>
>>>>>>> --
>>>>>>> Thanks,
>>>>>>> Jagan.
>>>>>>>
>>>>>>>
>>>>>> Thanks a lot for the reply.
>>>>>> Sure, will wait for your changes to go in.
>>>>>
>>>>> Will take some time go these changes on master.
>>>>>
>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>> git://git.denx.de/u-boot-spi.git
>>>>>
>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>> +ve result.
>>>>>
>>>> Tested the above tree on my board.
>>>> But, still the issues remain the same for me in all the three
>>>> cases(erase/read/write).
>>>>
>>>> Here is the short log of the read command..
>>>> DRA752 EVM # sf probe 0
>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>> CONFIG_SPI_FLASH_BAR
>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>> Total of 4091 byte(s) were the same
>>>>
>>>>
>>>> Erase: not able to do with a single command, need to issue for every
>>>> 0x10000
>>>> bytes.
>>>>
>>>> Write: Need to disable latch after every write to make it properly work.
>>>>
>>>> Is it possible for you to  give me  basic commands which you might have
>>>> ran
>>>> to confirm
>>>> the read/write and erase ??
>>> I tested the same part - for me i couldn't see the issues with SL256S
>>>
>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>> make debug ->   printf.
>>> Do the same test.! and send the log file.
>>>
>>> --
>>> Thanks,
>>> Jagan.
>> Here is the output log, no change..
>>
>>
>> DRA752 EVM # sf probe 0
>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>> DRA752 EVM # sf erase 0x0 0x10000
>> SF: 65536 bytes @ 0x0 Erased: OK
>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>> SF: 65536 bytes @ 0x0 Read: OK
>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>> Total of 4091 byte(s) were the same
>> DRA752 EVM #
>>
>>
>> Code change: for above output.
>> --- a/drivers/mtd/spi/spi_flash.c
>> +++ b/drivers/mtd/spi/spi_flash.c
>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>> unsigned long timeout)
>>
>>          ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>          if (ret) {
>> -               debug("SF: fail to read %s status register\n",
>> +               printf("SF: fail to read %s status register\n",
>>                          cmd == CMD_READ_STATUS ? "read" : "flag");
>>                  return ret;
>>          }
>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>> unsigned long timeout)
>>                  return 0;
>>
>>          /* Timed out */
>> -       debug("SF: time out!\n");
>> +       printf("SF: time out!\n");
>>          return -1;
>>   }
>>
> Ohh..
>
> - What if you erase the entire flash and read back, same result is it?
Yes.
> - please send the paths for config file for this board?
include/configs/dra7xx_evm.h

> --
> Thanks,
> Jagan.



From jagannadh.teki at gmail.com  Mon Jun 17 03:14:44 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 12:44:44 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BEB69B.5010902@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
 <51BEB3AB.6020603@ti.com>
 <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
 <51BEB69B.5010902@ti.com>
Message-ID: <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>

On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>
>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>> wrote:
>>>
>>> HI Jagan,
>>>
>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>
>>>> Hi Sourav,
>>>>
>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>>>> wrote:
>>>>>
>>>>> Hi Jagan,
>>>>>
>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>
>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>
>>>>>>> Hi Jagan,
>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>
>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>>>>>> trying to
>>>>>>>>>> make use of the existing spi_flash.c framework available at u-boot
>>>>>>>>>> for
>>>>>>>>>> erasing/reading/writing
>>>>>>>>>> into the flash device.
>>>>>>>>>>
>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>> using
>>>>>>>>>> S25FL256s flash device
>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>> above
>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>
>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>
>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>
>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>    - erases only first 0x20000 bytes of flash device, anything
>>>>>>>>>> above
>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>      issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>> bytes.
>>>>>>>>>>
>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>
>>>>>>>>>> 2. read
>>>>>>>>>>
>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>
>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>> boundary always shows zero.
>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>
>>>>>>>>>> For ex:
>>>>>>>>>>    DRA752 EVM # md 81000f00
>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>>>>>
>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>> which
>>>>>>>>>> is
>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> So, to get rid of the above issue, I switched to page read with
>>>>>>>>>> the
>>>>>>>>>> below patch[1],
>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>> [1]:
>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>    int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>> offset,
>>>>>>>>>>                   size_t len, void *data)
>>>>>>>>>>    {
>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>> +       int ret = 0;
>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>
>>>>>>>>>>           /* Handle memory-mapped SPI */
>>>>>>>>>>           if (flash->memory_map)
>>>>>>>>>>                   memcpy(data, flash->memory_map + offset, len);
>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>> +
>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>> +       for (actual = 0; actual<   len; actual += chunk_len) {
>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>> byte_addr);
>>>>>>>>>> +
>>>>>>>>>> +               cmd[1] = page_addr>>   8;
>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>> +
>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>> sizeof(cmd),
>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>> +               if (ret<   0) {
>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>> +                       break;
>>>>>>>>>> +               }
>>>>>>>>>>
>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>> +                       page_addr++;
>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>> +               }
>>>>>>>>>> +       }
>>>>>>>>>>
>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>> data,
>>>>>>>>>> len);
>>>>>>>>>> +       return ret;
>>>>>>>>>>    }
>>>>>>>>>>
>>>>>>>>>> Any idea about this?
>>>>>>>>>>
>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>     write not happening properly.
>>>>>>>>>>
>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>> page
>>>>>>>>>> is
>>>>>>>>>> not getting
>>>>>>>>>>           written.
>>>>>>>>>> Workaround:
>>>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>>>> program) and enable it
>>>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>>>> issue.
>>>>>>>>>>
>>>>>>>>>>    @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>> spi_flash
>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>                   if (ret)
>>>>>>>>>>                           break;
>>>>>>>>>>
>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>> +               if (ret<   0) {
>>>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>>>> +                       break;
>>>>>>>>>> +               }
>>>>>>>>>> +
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>
>>>>>>>>> Any Input on this?
>>>>>>>>
>>>>>>>>
>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>
>>>>>>>> We will continue this thread, after testing your part with these new
>>>>>>>> changes.
>>>>>>>>
>>>>>>>> I will intimate you once the push done.
>>>>>>>>
>>>>>>>> --
>>>>>>>> Thanks,
>>>>>>>> Jagan.
>>>>>>>>
>>>>>>>>
>>>>>>> Thanks a lot for the reply.
>>>>>>> Sure, will wait for your changes to go in.
>>>>>>
>>>>>>
>>>>>> Will take some time go these changes on master.
>>>>>>
>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>
>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>> +ve result.
>>>>>>
>>>>> Tested the above tree on my board.
>>>>> But, still the issues remain the same for me in all the three
>>>>> cases(erase/read/write).
>>>>>
>>>>> Here is the short log of the read command..
>>>>> DRA752 EVM # sf probe 0
>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>> CONFIG_SPI_FLASH_BAR
>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>> Total of 4091 byte(s) were the same
>>>>>
>>>>>
>>>>> Erase: not able to do with a single command, need to issue for every
>>>>> 0x10000
>>>>> bytes.
>>>>>
>>>>> Write: Need to disable latch after every write to make it properly
>>>>> work.
>>>>>
>>>>> Is it possible for you to  give me  basic commands which you might have
>>>>> ran
>>>>> to confirm
>>>>> the read/write and erase ??
>>>>
>>>> I tested the same part - for me i couldn't see the issues with SL256S
>>>>
>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>> make debug ->   printf.
>>>> Do the same test.! and send the log file.
>>>>
>>>> --
>>>> Thanks,
>>>> Jagan.
>>>
>>> Here is the output log, no change..
>>>
>>>
>>> DRA752 EVM # sf probe 0
>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>> DRA752 EVM # sf erase 0x0 0x10000
>>> SF: 65536 bytes @ 0x0 Erased: OK
>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>> SF: 65536 bytes @ 0x0 Read: OK
>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>> Total of 4091 byte(s) were the same
>>> DRA752 EVM #
>>>
>>>
>>> Code change: for above output.
>>> --- a/drivers/mtd/spi/spi_flash.c
>>> +++ b/drivers/mtd/spi/spi_flash.c
>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>> unsigned long timeout)
>>>
>>>          ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>
>>>          if (ret) {
>>> -               debug("SF: fail to read %s status register\n",
>>> +               printf("SF: fail to read %s status register\n",
>>>                          cmd == CMD_READ_STATUS ? "read" : "flag");
>>>                  return ret;
>>>          }
>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>> unsigned long timeout)
>>>                  return 0;
>>>
>>>          /* Timed out */
>>> -       debug("SF: time out!\n");
>>> +       printf("SF: time out!\n");
>>>          return -1;
>>>   }
>>>
>> Ohh..
>>
>> - What if you erase the entire flash and read back, same result is it?
>
> Yes.
>
>> - please send the paths for config file for this board?
>
> include/configs/dra7xx_evm.h

I couldn't find any SPI flash configs on above config file,
Can you point me the relevant configurations.

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 03:19:54 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 12:49:54 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>	<CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>	<51BEB3AB.6020603@ti.com>	<CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>	<51BEB69B.5010902@ti.com>
 <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>
Message-ID: <51BEB89A.3090105@ti.com>

On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>>> wrote:
>>>> HI Jagan,
>>>>
>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>> Hi Sourav,
>>>>>
>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>>>>> wrote:
>>>>>> Hi Jagan,
>>>>>>
>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>> Hi Jagan,
>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I am
>>>>>>>>>>> trying to
>>>>>>>>>>> make use of the existing spi_flash.c framework available at u-boot
>>>>>>>>>>> for
>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>> into the flash device.
>>>>>>>>>>>
>>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>>> using
>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>>> above
>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>
>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>
>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>
>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>     - erases only first 0x20000 bytes of flash device, anything
>>>>>>>>>>> above
>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>       issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>>> bytes.
>>>>>>>>>>>
>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>
>>>>>>>>>>> 2. read
>>>>>>>>>>>
>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>
>>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>
>>>>>>>>>>> For ex:
>>>>>>>>>>>     DRA752 EVM # md 81000f00
>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff    ................
>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000    ................
>>>>>>>>>>>
>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>>> which
>>>>>>>>>>> is
>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> So, to get rid of the above issue, I switched to page read with
>>>>>>>>>>> the
>>>>>>>>>>> below patch[1],
>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>> [1]:
>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>     int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>>> offset,
>>>>>>>>>>>                    size_t len, void *data)
>>>>>>>>>>>     {
>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>
>>>>>>>>>>>            /* Handle memory-mapped SPI */
>>>>>>>>>>>            if (flash->memory_map)
>>>>>>>>>>>                    memcpy(data, flash->memory_map + offset, len);
>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>> +
>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>> +       for (actual = 0; actual<    len; actual += chunk_len) {
>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>> byte_addr);
>>>>>>>>>>> +
>>>>>>>>>>> +               cmd[1] = page_addr>>    8;
>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>> +
>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>> +               if (ret<    0) {
>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>> +                       break;
>>>>>>>>>>> +               }
>>>>>>>>>>>
>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>> +               }
>>>>>>>>>>> +       }
>>>>>>>>>>>
>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>>> data,
>>>>>>>>>>> len);
>>>>>>>>>>> +       return ret;
>>>>>>>>>>>     }
>>>>>>>>>>>
>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>
>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>      write not happening properly.
>>>>>>>>>>>
>>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>>> page
>>>>>>>>>>> is
>>>>>>>>>>> not getting
>>>>>>>>>>>            written.
>>>>>>>>>>> Workaround:
>>>>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>>>>> program) and enable it
>>>>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>>>>> issue.
>>>>>>>>>>>
>>>>>>>>>>>     @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>>> spi_flash
>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>                    if (ret)
>>>>>>>>>>>                            break;
>>>>>>>>>>>
>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>> +               if (ret<    0) {
>>>>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>>>>> +                       break;
>>>>>>>>>>> +               }
>>>>>>>>>>> +
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>
>>>>>>>>>> Any Input on this?
>>>>>>>>>
>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>
>>>>>>>>> We will continue this thread, after testing your part with these new
>>>>>>>>> changes.
>>>>>>>>>
>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Thanks,
>>>>>>>>> Jagan.
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Thanks a lot for the reply.
>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>
>>>>>>> Will take some time go these changes on master.
>>>>>>>
>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>
>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>> +ve result.
>>>>>>>
>>>>>> Tested the above tree on my board.
>>>>>> But, still the issues remain the same for me in all the three
>>>>>> cases(erase/read/write).
>>>>>>
>>>>>> Here is the short log of the read command..
>>>>>> DRA752 EVM # sf probe 0
>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>> Total of 4091 byte(s) were the same
>>>>>>
>>>>>>
>>>>>> Erase: not able to do with a single command, need to issue for every
>>>>>> 0x10000
>>>>>> bytes.
>>>>>>
>>>>>> Write: Need to disable latch after every write to make it properly
>>>>>> work.
>>>>>>
>>>>>> Is it possible for you to  give me  basic commands which you might have
>>>>>> ran
>>>>>> to confirm
>>>>>> the read/write and erase ??
>>>>> I tested the same part - for me i couldn't see the issues with SL256S
>>>>>
>>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>>> make debug ->    printf.
>>>>> Do the same test.! and send the log file.
>>>>>
>>>>> --
>>>>> Thanks,
>>>>> Jagan.
>>>> Here is the output log, no change..
>>>>
>>>>
>>>> DRA752 EVM # sf probe 0
>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>> Total of 4091 byte(s) were the same
>>>> DRA752 EVM #
>>>>
>>>>
>>>> Code change: for above output.
>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>>> unsigned long timeout)
>>>>
>>>>           ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>
>>>>           if (ret) {
>>>> -               debug("SF: fail to read %s status register\n",
>>>> +               printf("SF: fail to read %s status register\n",
>>>>                           cmd == CMD_READ_STATUS ? "read" : "flag");
>>>>                   return ret;
>>>>           }
>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>>> unsigned long timeout)
>>>>                   return 0;
>>>>
>>>>           /* Timed out */
>>>> -       debug("SF: time out!\n");
>>>> +       printf("SF: time out!\n");
>>>>           return -1;
>>>>    }
>>>>
>>> Ohh..
>>>
>>> - What if you erase the entire flash and read back, same result is it?
>> Yes.
>>
>>> - please send the paths for config file for this board?
>> include/configs/dra7xx_evm.h
> I couldn't find any SPI flash configs on above config file,
> Can you point me the relevant configurations.
>
Following are the configuration details for spi..
#define CONFIG_SPI_FLASH_BAR
#define CONFIG_TI_QSPI
#define CONFIG_SPI_FLASH
#define CONFIG_SPI_FLASH_SPANSION
#define CONFIG_CMD_SF
#define CONFIG_CMD_SPI
#define CONFIG_SF_DEFAULT_SPEED         12000000
#define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3

/* SPI SPL */
#define CONFIG_SPL_SPI_SUPPORT
#define CONFIG_SPL_SPI_LOAD
#define CONFIG_SPL_SPI_FLASH_SUPPORT
#define CONFIG_SPL_SPI_BUS              0
#define CONFIG_SPL_SPI_CS               0
#define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000


> --
> Thanks,
> Jagan.



From jagannadh.teki at gmail.com  Mon Jun 17 03:34:54 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 13:04:54 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BEB89A.3090105@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
 <51BEB3AB.6020603@ti.com>
 <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
 <51BEB69B.5010902@ti.com>
 <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>
 <51BEB89A.3090105@ti.com>
Message-ID: <CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>

On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>
>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>> wrote:
>>>
>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>
>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>> wrote:
>>>>>
>>>>> HI Jagan,
>>>>>
>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>
>>>>>> Hi Sourav,
>>>>>>
>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> Hi Jagan,
>>>>>>>
>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>
>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>
>>>>>>>>> Hi Jagan,
>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>
>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I
>>>>>>>>>>>> am
>>>>>>>>>>>> trying to
>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>> u-boot
>>>>>>>>>>>> for
>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>
>>>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>>>> using
>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>>>> above
>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>
>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>
>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>
>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>     - erases only first 0x20000 bytes of flash device, anything
>>>>>>>>>>>> above
>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>       issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>>>> bytes.
>>>>>>>>>>>>
>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>
>>>>>>>>>>>> 2. read
>>>>>>>>>>>>
>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>
>>>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>
>>>>>>>>>>>> For ex:
>>>>>>>>>>>>     DRA752 EVM # md 81000f00
>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>> ................
>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>> ................
>>>>>>>>>>>>
>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>>>> which
>>>>>>>>>>>> is
>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read with
>>>>>>>>>>>> the
>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>> [1]:
>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>     int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>>>> offset,
>>>>>>>>>>>>                    size_t len, void *data)
>>>>>>>>>>>>     {
>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>
>>>>>>>>>>>>            /* Handle memory-mapped SPI */
>>>>>>>>>>>>            if (flash->memory_map)
>>>>>>>>>>>>                    memcpy(data, flash->memory_map + offset,
>>>>>>>>>>>> len);
>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>> +
>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>> +       for (actual = 0; actual<    len; actual += chunk_len) {
>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>> +
>>>>>>>>>>>> +               cmd[1] = page_addr>>    8;
>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>> +
>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>> +               if (ret<    0) {
>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>> +                       break;
>>>>>>>>>>>> +               }
>>>>>>>>>>>>
>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>> +               }
>>>>>>>>>>>> +       }
>>>>>>>>>>>>
>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>>>> data,
>>>>>>>>>>>> len);
>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>     }
>>>>>>>>>>>>
>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>
>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>      write not happening properly.
>>>>>>>>>>>>
>>>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>>>> page
>>>>>>>>>>>> is
>>>>>>>>>>>> not getting
>>>>>>>>>>>>            written.
>>>>>>>>>>>> Workaround:
>>>>>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>>>>>> issue.
>>>>>>>>>>>>
>>>>>>>>>>>>     @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>>>> spi_flash
>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>                    if (ret)
>>>>>>>>>>>>                            break;
>>>>>>>>>>>>
>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>> +               if (ret<    0) {
>>>>>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>>>>>> +                       break;
>>>>>>>>>>>> +               }
>>>>>>>>>>>> +
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>
>>>>>>>>>>> Any Input on this?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>
>>>>>>>>>> We will continue this thread, after testing your part with these
>>>>>>>>>> new
>>>>>>>>>> changes.
>>>>>>>>>>
>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Thanks,
>>>>>>>>>> Jagan.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>
>>>>>>>>
>>>>>>>> Will take some time go these changes on master.
>>>>>>>>
>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>
>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>> +ve result.
>>>>>>>>
>>>>>>> Tested the above tree on my board.
>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>> cases(erase/read/write).
>>>>>>>
>>>>>>> Here is the short log of the read command..
>>>>>>> DRA752 EVM # sf probe 0
>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>
>>>>>>>
>>>>>>> Erase: not able to do with a single command, need to issue for every
>>>>>>> 0x10000
>>>>>>> bytes.
>>>>>>>
>>>>>>> Write: Need to disable latch after every write to make it properly
>>>>>>> work.
>>>>>>>
>>>>>>> Is it possible for you to  give me  basic commands which you might
>>>>>>> have
>>>>>>> ran
>>>>>>> to confirm
>>>>>>> the read/write and erase ??
>>>>>>
>>>>>> I tested the same part - for me i couldn't see the issues with SL256S
>>>>>>
>>>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>>>> make debug ->    printf.
>>>>>> Do the same test.! and send the log file.
>>>>>>
>>>>>> --
>>>>>> Thanks,
>>>>>> Jagan.
>>>>>
>>>>> Here is the output log, no change..
>>>>>
>>>>>
>>>>> DRA752 EVM # sf probe 0
>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>> Total of 4091 byte(s) were the same
>>>>> DRA752 EVM #
>>>>>
>>>>>
>>>>> Code change: for above output.
>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>>>> unsigned long timeout)
>>>>>
>>>>>           ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>
>>>>>           if (ret) {
>>>>> -               debug("SF: fail to read %s status register\n",
>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>                           cmd == CMD_READ_STATUS ? "read" : "flag");
>>>>>                   return ret;
>>>>>           }
>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>> *flash,
>>>>> unsigned long timeout)
>>>>>                   return 0;
>>>>>
>>>>>           /* Timed out */
>>>>> -       debug("SF: time out!\n");
>>>>> +       printf("SF: time out!\n");
>>>>>           return -1;
>>>>>    }
>>>>>
>>>> Ohh..
>>>>
>>>> - What if you erase the entire flash and read back, same result is it?
>>>
>>> Yes.
>>>
>>>> - please send the paths for config file for this board?
>>>
>>> include/configs/dra7xx_evm.h
>>
>> I couldn't find any SPI flash configs on above config file,
>> Can you point me the relevant configurations.
>>
> Following are the configuration details for spi..
> #define CONFIG_SPI_FLASH_BAR
> #define CONFIG_TI_QSPI

Where can i find this?

> #define CONFIG_SPI_FLASH
> #define CONFIG_SPI_FLASH_SPANSION
> #define CONFIG_CMD_SF
> #define CONFIG_CMD_SPI
> #define CONFIG_SF_DEFAULT_SPEED         12000000
> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>
> /* SPI SPL */
> #define CONFIG_SPL_SPI_SUPPORT
> #define CONFIG_SPL_SPI_LOAD
> #define CONFIG_SPL_SPI_FLASH_SUPPORT
> #define CONFIG_SPL_SPI_BUS              0
> #define CONFIG_SPL_SPI_CS               0
> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 03:41:35 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 13:11:35 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>	<CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>	<51BEB3AB.6020603@ti.com>	<CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>	<51BEB69B.5010902@ti.com>	<CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>	<51BEB89A.3090105@ti.com>
 <CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>
Message-ID: <51BEBDAF.7000201@ti.com>

Hi Jagan,
On Monday 17 June 2013 01:04 PM, Jagan Teki wrote:
> On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>>> wrote:
>>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>> wrote:
>>>>>> HI Jagan,
>>>>>>
>>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>> Hi Sourav,
>>>>>>>
>>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>>> wrote:
>>>>>>>> Hi Jagan,
>>>>>>>>
>>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>> Hi Jagan,
>>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I
>>>>>>>>>>>>> am
>>>>>>>>>>>>> trying to
>>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>>> u-boot
>>>>>>>>>>>>> for
>>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>>
>>>>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>>>>> using
>>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>>>>> above
>>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>>
>>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>>
>>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>>
>>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>>      - erases only first 0x20000 bytes of flash device, anything
>>>>>>>>>>>>> above
>>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>>        issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>>>>> bytes.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>>
>>>>>>>>>>>>> 2. read
>>>>>>>>>>>>>
>>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>>
>>>>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>>
>>>>>>>>>>>>> For ex:
>>>>>>>>>>>>>      DRA752 EVM # md 81000f00
>>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>> ................
>>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>>> ................
>>>>>>>>>>>>>
>>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>>>>> which
>>>>>>>>>>>>> is
>>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read with
>>>>>>>>>>>>> the
>>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>>> [1]:
>>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct spi_flash
>>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>>      int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>                     size_t len, void *data)
>>>>>>>>>>>>>      {
>>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>>
>>>>>>>>>>>>>             /* Handle memory-mapped SPI */
>>>>>>>>>>>>>             if (flash->memory_map)
>>>>>>>>>>>>>                     memcpy(data, flash->memory_map + offset,
>>>>>>>>>>>>> len);
>>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>>> +       for (actual = 0; actual<     len; actual += chunk_len) {
>>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +               cmd[1] = page_addr>>     8;
>>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>>> +               if (ret<     0) {
>>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>
>>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>>> +               }
>>>>>>>>>>>>> +       }
>>>>>>>>>>>>>
>>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>>>>> data,
>>>>>>>>>>>>> len);
>>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>>      }
>>>>>>>>>>>>>
>>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>>
>>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>>       write not happening properly.
>>>>>>>>>>>>>
>>>>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>>>>> page
>>>>>>>>>>>>> is
>>>>>>>>>>>>> not getting
>>>>>>>>>>>>>             written.
>>>>>>>>>>>>> Workaround:
>>>>>>>>>>>>> I did a write disable latch at the end of every write cycle(page
>>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the above
>>>>>>>>>>>>> issue.
>>>>>>>>>>>>>
>>>>>>>>>>>>>      @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>>                     if (ret)
>>>>>>>>>>>>>                             break;
>>>>>>>>>>>>>
>>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>>> +               if (ret<     0) {
>>>>>>>>>>>>> +                       printf("SF: disabling write failed\n");
>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>> +               }
>>>>>>>>>>>>> +
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>>
>>>>>>>>>>>> Any Input on this?
>>>>>>>>>>>
>>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>>
>>>>>>>>>>> We will continue this thread, after testing your part with these
>>>>>>>>>>> new
>>>>>>>>>>> changes.
>>>>>>>>>>>
>>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Jagan.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>>
>>>>>>>>> Will take some time go these changes on master.
>>>>>>>>>
>>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>>
>>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>>> +ve result.
>>>>>>>>>
>>>>>>>> Tested the above tree on my board.
>>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>>> cases(erase/read/write).
>>>>>>>>
>>>>>>>> Here is the short log of the read command..
>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>
>>>>>>>>
>>>>>>>> Erase: not able to do with a single command, need to issue for every
>>>>>>>> 0x10000
>>>>>>>> bytes.
>>>>>>>>
>>>>>>>> Write: Need to disable latch after every write to make it properly
>>>>>>>> work.
>>>>>>>>
>>>>>>>> Is it possible for you to  give me  basic commands which you might
>>>>>>>> have
>>>>>>>> ran
>>>>>>>> to confirm
>>>>>>>> the read/write and erase ??
>>>>>>> I tested the same part - for me i couldn't see the issues with SL256S
>>>>>>>
>>>>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>>>>> make debug ->     printf.
>>>>>>> Do the same test.! and send the log file.
>>>>>>>
>>>>>>> --
>>>>>>> Thanks,
>>>>>>> Jagan.
>>>>>> Here is the output log, no change..
>>>>>>
>>>>>>
>>>>>> DRA752 EVM # sf probe 0
>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>> Total of 4091 byte(s) were the same
>>>>>> DRA752 EVM #
>>>>>>
>>>>>>
>>>>>> Code change: for above output.
>>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash,
>>>>>> unsigned long timeout)
>>>>>>
>>>>>>            ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>>
>>>>>>            if (ret) {This is still not sent out for review. I can send you the patch 
>>>>>> -               debug("SF: fail to read %s status register\n",
>>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>>                            cmd == CMD_READ_STATUS ? "read" : "flag");
>>>>>>                    return ret;
>>>>>>            }
>>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>> *flash,
>>>>>> unsigned long timeout)
>>>>>>                    return 0;
>>>>>>
>>>>>>            /* Timed out */
>>>>>> -       debug("SF: time out!\n");
>>>>>> +       printf("SF: time out!\n");
>>>>>>            return -1;
>>>>>>     }
>>>>>>
>>>>> Ohh..
>>>>>
>>>>> - What if you erase the entire flash and read back, same result is it?
>>>> Yes.
>>>>
>>>>> - please send the paths for config file for this board?
>>>> include/configs/dra7xx_evm.h
>>> I couldn't find any SPI flash configs on above config file,
>>> Can you point me the relevant configurations.
>>>
>> Following are the configuration details for spi..
>> #define CONFIG_SPI_FLASH_BAR
>> #define CONFIG_TI_QSPI
> Where can i find this?
>
I have attached the required patches in the thread.
Patch 0002 is my ti qspi controller.
Patch 0004 is my workarounds done for the all the issues
mentioned in the $subject patch.
Patch 0001 and 0002 are other configs.
>> #define CONFIG_SPI_FLASH
>> #define CONFIG_SPI_FLASH_SPANSION
>> #define CONFIG_CMD_SF
>> #define CONFIG_CMD_SPI
>> #define CONFIG_SF_DEFAULT_SPEED         12000000
>> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>>
>> /* SPI SPL */
>> #define CONFIG_SPL_SPI_SUPPORT
>> #define CONFIG_SPL_SPI_LOAD
>> #define CONFIG_SPL_SPI_FLASH_SUPPORT
>> #define CONFIG_SPL_SPI_BUS              0
>> #define CONFIG_SPL_SPI_CS               0
>> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000
> --
> Thanks,
> Jagan.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-omap5-add-qspi-support.patch
Type: text/x-diff
Size: 3683 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130617/759e5efa/attachment-0004.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-spi-add-TI-QSPI-driver.patch
Type: text/x-diff
Size: 7593 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130617/759e5efa/attachment-0005.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-dra7xx_evm-add-SPL-API-QSPI-and-serial-flash-support.patch
Type: text/x-diff
Size: 2224 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130617/759e5efa/attachment-0006.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0004-drivers-mtd-spi-Modify-read-write-command-for-sfl256.patch
Type: text/x-diff
Size: 2420 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130617/759e5efa/attachment-0007.bin>

From jagannadh.teki at gmail.com  Mon Jun 17 04:39:37 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 14:09:37 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BEBDAF.7000201@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
 <51BEB3AB.6020603@ti.com>
 <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
 <51BEB69B.5010902@ti.com>
 <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>
 <51BEB89A.3090105@ti.com>
 <CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>
 <51BEBDAF.7000201@ti.com>
Message-ID: <CAD6G_RSog7AJwfJigewGnF8C=Dw3yWv38Q8hR4xaayjmicQXFw@mail.gmail.com>

On Mon, Jun 17, 2013 at 1:11 PM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> Hi Jagan,
>
> On Monday 17 June 2013 01:04 PM, Jagan Teki wrote:
>>
>> On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar<sourav.poddar at ti.com>
>> wrote:
>>>
>>> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>>>
>>>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>> wrote:
>>>>>
>>>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>>>
>>>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> HI Jagan,
>>>>>>>
>>>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>>>
>>>>>>>> Hi Sourav,
>>>>>>>>
>>>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav
>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> Hi Jagan,
>>>>>>>>>
>>>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>>>
>>>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I
>>>>>>>>>>>>>> am
>>>>>>>>>>>>>> trying to
>>>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>>>> u-boot
>>>>>>>>>>>>>> for
>>>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>>>>>> using
>>>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>>>>>> above
>>>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>>>      - erases only first 0x20000 bytes of flash device,
>>>>>>>>>>>>>> anything
>>>>>>>>>>>>>> above
>>>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>>>        issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>>>>>> bytes.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 2. read
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> For ex:
>>>>>>>>>>>>>>      DRA752 EVM # md 81000f00
>>>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>>>>>> which
>>>>>>>>>>>>>> is
>>>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read
>>>>>>>>>>>>>> with
>>>>>>>>>>>>>> the
>>>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>>>> [1]:
>>>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct
>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>>>      int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>                     size_t len, void *data)
>>>>>>>>>>>>>>      {
>>>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>             /* Handle memory-mapped SPI */
>>>>>>>>>>>>>>             if (flash->memory_map)
>>>>>>>>>>>>>>                     memcpy(data, flash->memory_map + offset,
>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>>>> +       for (actual = 0; actual<     len; actual += chunk_len)
>>>>>>>>>>>>>> {
>>>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +               cmd[1] = page_addr>>     8;
>>>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>>>> +               if (ret<     0) {
>>>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>> +       }
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>>>>>> data,
>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>>>      }
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>>>       write not happening properly.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>>>>>> page
>>>>>>>>>>>>>> is
>>>>>>>>>>>>>> not getting
>>>>>>>>>>>>>>             written.
>>>>>>>>>>>>>> Workaround:
>>>>>>>>>>>>>> I did a write disable latch at the end of every write
>>>>>>>>>>>>>> cycle(page
>>>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the
>>>>>>>>>>>>>> above
>>>>>>>>>>>>>> issue.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>      @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>>>                     if (ret)
>>>>>>>>>>>>>>                             break;
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>>>> +               if (ret<     0) {
>>>>>>>>>>>>>> +                       printf("SF: disabling write
>>>>>>>>>>>>>> failed\n");
>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>>>
>>>>>>>>>>>>> Any Input on this?
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>>>
>>>>>>>>>>>> We will continue this thread, after testing your part with these
>>>>>>>>>>>> new
>>>>>>>>>>>> changes.
>>>>>>>>>>>>
>>>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Jagan.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Will take some time go these changes on master.
>>>>>>>>>>
>>>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>>>
>>>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>>>> +ve result.
>>>>>>>>>>
>>>>>>>>> Tested the above tree on my board.
>>>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>>>> cases(erase/read/write).
>>>>>>>>>
>>>>>>>>> Here is the short log of the read command..
>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Erase: not able to do with a single command, need to issue for
>>>>>>>>> every
>>>>>>>>> 0x10000
>>>>>>>>> bytes.
>>>>>>>>>
>>>>>>>>> Write: Need to disable latch after every write to make it properly
>>>>>>>>> work.
>>>>>>>>>
>>>>>>>>> Is it possible for you to  give me  basic commands which you might
>>>>>>>>> have
>>>>>>>>> ran
>>>>>>>>> to confirm
>>>>>>>>> the read/write and erase ??
>>>>>>>>
>>>>>>>> I tested the same part - for me i couldn't see the issues with
>>>>>>>> SL256S
>>>>>>>>
>>>>>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>>>>>> make debug ->     printf.
>>>>>>>> Do the same test.! and send the log file.
>>>>>>>>
>>>>>>>> --
>>>>>>>> Thanks,
>>>>>>>> Jagan.
>>>>>>>
>>>>>>> Here is the output log, no change..
>>>>>>>
>>>>>>>
>>>>>>> DRA752 EVM # sf probe 0
>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>> Total of 4091 byte(s) were the same
>>>>>>> DRA752 EVM #
>>>>>>>
>>>>>>>
>>>>>>> Code change: for above output.
>>>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>> *flash,
>>>>>>> unsigned long timeout)
>>>>>>>
>>>>>>>            ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>>>
>>>>>>>            if (ret) {This is still not sent out for review. I can
>>>>>>> send you the patch -               debug("SF: fail to read %s status
>>>>>>> register\n",
>>>>>>>
>>>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>>>                            cmd == CMD_READ_STATUS ? "read" : "flag");
>>>>>>>                    return ret;
>>>>>>>            }
>>>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>> *flash,
>>>>>>> unsigned long timeout)
>>>>>>>                    return 0;
>>>>>>>
>>>>>>>            /* Timed out */
>>>>>>> -       debug("SF: time out!\n");
>>>>>>> +       printf("SF: time out!\n");
>>>>>>>            return -1;
>>>>>>>     }
>>>>>>>
>>>>>> Ohh..
>>>>>>
>>>>>> - What if you erase the entire flash and read back, same result is it?
>>>>>
>>>>> Yes.
>>>>>
>>>>>> - please send the paths for config file for this board?
>>>>>
>>>>> include/configs/dra7xx_evm.h
>>>>
>>>> I couldn't find any SPI flash configs on above config file,
>>>> Can you point me the relevant configurations.
>>>>
>>> Following are the configuration details for spi..
>>> #define CONFIG_SPI_FLASH_BAR
>>> #define CONFIG_TI_QSPI
>>
>> Where can i find this?
>>
> I have attached the required patches in the thread.
> Patch 0002 is my ti qspi controller.
> Patch 0004 is my workarounds done for the all the issues
> mentioned in the $subject patch.
> Patch 0001 and 0002 are other configs.
>
>>> #define CONFIG_SPI_FLASH
>>> #define CONFIG_SPI_FLASH_SPANSION
>>> #define CONFIG_CMD_SF
>>> #define CONFIG_CMD_SPI
>>> #define CONFIG_SF_DEFAULT_SPEED         12000000
>>> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>>>
>>> /* SPI SPL */
>>> #define CONFIG_SPL_SPI_SUPPORT
>>> #define CONFIG_SPL_SPI_LOAD
>>> #define CONFIG_SPL_SPI_FLASH_SUPPORT
>>> #define CONFIG_SPL_SPI_BUS              0
>>> #define CONFIG_SPL_SPI_CS               0
>>> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000
>

Ohh... these drivers not yet in mainline.Ok?

Did you ever tested any of other flash parts (other 256S) with these drivers.
Let me give some time to go through these drivers code.

Do you confident that ti_qspi.c doesn't have any issues while
processing SPI transactions.?

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 04:45:42 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 14:15:42 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RSog7AJwfJigewGnF8C=Dw3yWv38Q8hR4xaayjmicQXFw@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>	<CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>	<51BEB3AB.6020603@ti.com>	<CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>	<51BEB69B.5010902@ti.com>	<CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>	<51BEB89A.3090105@ti.com>	<CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>	<51BEBDAF.7000201@ti.com>
 <CAD6G_RSog7AJwfJigewGnF8C=Dw3yWv38Q8hR4xaayjmicQXFw@mail.gmail.com>
Message-ID: <51BECCB6.3030304@ti.com>

On Monday 17 June 2013 02:09 PM, Jagan Teki wrote:
> On Mon, Jun 17, 2013 at 1:11 PM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> Hi Jagan,
>>
>> On Monday 17 June 2013 01:04 PM, Jagan Teki wrote:
>>> On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar<sourav.poddar at ti.com>
>>> wrote:
>>>> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>>>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>> wrote:
>>>>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>>> wrote:
>>>>>>>> HI Jagan,
>>>>>>>>
>>>>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>>>> Hi Sourav,
>>>>>>>>>
>>>>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav
>>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>>> wrote:
>>>>>>>>>> Hi Jagan,
>>>>>>>>>>
>>>>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level. I
>>>>>>>>>>>>>>> am
>>>>>>>>>>>>>>> trying to
>>>>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>>>>> u-boot
>>>>>>>>>>>>>>> for
>>>>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> There are several issues(mentioned below), which I faced while
>>>>>>>>>>>>>>> using
>>>>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which the
>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>>>>       - erases only first 0x20000 bytes of flash device,
>>>>>>>>>>>>>>> anything
>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>>>>         issue separate commands after 0x20000 for every 0x10000
>>>>>>>>>>>>>>> bytes.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 2. read
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Read is not happening properly. The last few byte along the 4k
>>>>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> For ex:
>>>>>>>>>>>>>>>       DRA752 EVM # md 81000f00
>>>>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows 000000
>>>>>>>>>>>>>>> which
>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read
>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>>>>> [1]:
>>>>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct
>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>>>>       int spi_flash_cmd_read_fast(struct spi_flash *flash, u32
>>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>>                      size_t len, void *data)
>>>>>>>>>>>>>>>       {
>>>>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>              /* Handle memory-mapped SPI */
>>>>>>>>>>>>>>>              if (flash->memory_map)
>>>>>>>>>>>>>>>                      memcpy(data, flash->memory_map + offset,
>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>>>>> +       for (actual = 0; actual<      len; actual += chunk_len)
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +               cmd[1] = page_addr>>      8;
>>>>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>>>>> +               if (ret<      0) {
>>>>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>> +       }
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd, sizeof(cmd),
>>>>>>>>>>>>>>> data,
>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>>>>       }
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>>>>        write not happening properly.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> observations: only able to write single page, anything after a
>>>>>>>>>>>>>>> page
>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>> not getting
>>>>>>>>>>>>>>>              written.
>>>>>>>>>>>>>>> Workaround:
>>>>>>>>>>>>>>> I did a write disable latch at the end of every write
>>>>>>>>>>>>>>> cycle(page
>>>>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the
>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>> issue.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>       @@ -117,6 +117,12 @@ int spi_flash_cmd_write_multi(struct
>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>>>>                      if (ret)
>>>>>>>>>>>>>>>                              break;
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>>>>> +               if (ret<      0) {
>>>>>>>>>>>>>>> +                       printf("SF: disabling write
>>>>>>>>>>>>>>> failed\n");
>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Any Input on this?
>>>>>>>>>>>>>
>>>>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>>>>
>>>>>>>>>>>>> We will continue this thread, after testing your part with these
>>>>>>>>>>>>> new
>>>>>>>>>>>>> changes.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Jagan.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>>>>
>>>>>>>>>>> Will take some time go these changes on master.
>>>>>>>>>>>
>>>>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>>>>
>>>>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>>>>> +ve result.
>>>>>>>>>>>
>>>>>>>>>> Tested the above tree on my board.
>>>>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>>>>> cases(erase/read/write).
>>>>>>>>>>
>>>>>>>>>> Here is the short log of the read command..
>>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Erase: not able to do with a single command, need to issue for
>>>>>>>>>> every
>>>>>>>>>> 0x10000
>>>>>>>>>> bytes.
>>>>>>>>>>
>>>>>>>>>> Write: Need to disable latch after every write to make it properly
>>>>>>>>>> work.
>>>>>>>>>>
>>>>>>>>>> Is it possible for you to  give me  basic commands which you might
>>>>>>>>>> have
>>>>>>>>>> ran
>>>>>>>>>> to confirm
>>>>>>>>>> the read/write and erase ??
>>>>>>>>> I tested the same part - for me i couldn't see the issues with
>>>>>>>>> SL256S
>>>>>>>>>
>>>>>>>>> OK! can enable the log on poll function, spi_flash_cmd_wait_ready()
>>>>>>>>> make debug ->      printf.
>>>>>>>>> Do the same test.! and send the log file.
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Thanks,
>>>>>>>>> Jagan.
>>>>>>>> Here is the output log, no change..
>>>>>>>>
>>>>>>>>
>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>> DRA752 EVM #
>>>>>>>>
>>>>>>>>
>>>>>>>> Code change: for above output.
>>>>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>> *flash,
>>>>>>>> unsigned long timeout)
>>>>>>>>
>>>>>>>>             ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>>>>
>>>>>>>>             if (ret) {This is still not sent out for review. I can
>>>>>>>> send you the patch -               debug("SF: fail to read %s status
>>>>>>>> register\n",
>>>>>>>>
>>>>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>>>>                             cmd == CMD_READ_STATUS ? "read" : "flag");
>>>>>>>>                     return ret;
>>>>>>>>             }
>>>>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>> *flash,
>>>>>>>> unsigned long timeout)
>>>>>>>>                     return 0;
>>>>>>>>
>>>>>>>>             /* Timed out */
>>>>>>>> -       debug("SF: time out!\n");
>>>>>>>> +       printf("SF: time out!\n");
>>>>>>>>             return -1;
>>>>>>>>      }
>>>>>>>>
>>>>>>> Ohh..
>>>>>>>
>>>>>>> - What if you erase the entire flash and read back, same result is it?
>>>>>> Yes.
>>>>>>
>>>>>>> - please send the paths for config file for this board?
>>>>>> include/configs/dra7xx_evm.h
>>>>> I couldn't find any SPI flash configs on above config file,
>>>>> Can you point me the relevant configurations.
>>>>>
>>>> Following are the configuration details for spi..
>>>> #define CONFIG_SPI_FLASH_BAR
>>>> #define CONFIG_TI_QSPI
>>> Where can i find this?
>>>
>> I have attached the required patches in the thread.
>> Patch 0002 is my ti qspi controller.
>> Patch 0004 is my workarounds done for the all the issues
>> mentioned in the $subject patch.
>> Patch 0001 and 0002 are other configs.
>>
>>>> #define CONFIG_SPI_FLASH
>>>> #define CONFIG_SPI_FLASH_SPANSION
>>>> #define CONFIG_CMD_SF
>>>> #define CONFIG_CMD_SPI
>>>> #define CONFIG_SF_DEFAULT_SPEED         12000000
>>>> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>>>>
>>>> /* SPI SPL */
>>>> #define CONFIG_SPL_SPI_SUPPORT
>>>> #define CONFIG_SPL_SPI_LOAD
>>>> #define CONFIG_SPL_SPI_FLASH_SUPPORT
>>>> #define CONFIG_SPL_SPI_BUS              0
>>>> #define CONFIG_SPL_SPI_CS               0
>>>> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000
> Ohh... these drivers not yet in mainline.Ok?
>
They are not in mainline, yet. Due to above mentioned issue, I have not
  posted it yet.
> Did you ever tested any of other flash parts (other 256S) with these drivers.
> Let me give some time to go through these drivers code.
>
No, I don,t have any other board which has any other flash device.

> Do you confident that ti_qspi.c doesn't have any issues while
> processing SPI transactions.?
>
I tried putting a lot of prints, which does not show any obvious error.

Moreover, with the workaround mentioned before, things work fine.

> --
> Thanks,
> Jagan.



From helmut.raiger at hale.at  Mon Jun 17 05:02:54 2013
From: helmut.raiger at hale.at (Helmut Raiger)
Date: Mon, 17 Jun 2013 11:02:54 +0200
Subject: UBIFS: How to reserve space to be used right before power cut
In-Reply-To: <20130613162028.3d17bac2@parrot.com>
References: <20130613135031.59037201@parrot.com>
 <1142745477.330790.1371130164128.JavaMail.root@mail.hale>
 <20130613162028.3d17bac2@parrot.com>
Message-ID: <51BED0BE.2090701@hale.at>

On 06/13/2013 04:20 PM, Matthieu CASTET wrote:
> Not gluebi
>
> you have a userspace inferface to ubi : /usr/include/mtd/ubi-user.h
>
>
> You could create a small ubi volume (dynamic or static) of 1 LEB next to
> ubifs (on the same ubi device).
> When you start you make sure the LEB have enough space and that the LEB
> is mapped.
>
> on a power fail signal you write the LEB with your data. Because the
> LEB is already mapped, the write should be imediate.
>
>
> If the ubi volume is on the same ubi device than ubifs, the wear
> leveling will be shared with ubifs.
>

I digged the UBI sources and still have the feeling this won't work:

1) There seems to be no way to (long term) protect a PEB from being
moved by the wear leveling sub-system (even scrubbing on bit-flips,
which may be induced by read-disturbances (reads on nearby pages)).

2) Temporary protection of a PEB is not really time specific, but depends
on global PEB erase action (i.e. anything UBIFS does on the same device),
which is something I can't control.

My impression is, that UBI simply does not support this sort of
application well. Unmoveable blocks will have a low erase count
(below average), which is exactly what the WL should avoid.

However I've never timed such a move operation:
a) move content to a new unused PEB
b) schedule original PEB for erasure
It might fit into my timing requirements, but will probably be heavily
influenced by system load and priorities.

Helmut

--
Scanned by MailScanner.



From jagannadh.teki at gmail.com  Mon Jun 17 05:58:28 2013
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 17 Jun 2013 15:28:28 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <51BECCB6.3030304@ti.com>
References: <51B82388.2000909@ti.com> <51BB29A5.3000100@ti.com>
 <51BB2AE4.4020109@gmail.com> <51BB2C2B.1010404@ti.com>
 <51BC93AF.5080808@gmail.com> <51BEA955.9080907@ti.com>
 <CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>
 <51BEB3AB.6020603@ti.com>
 <CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>
 <51BEB69B.5010902@ti.com>
 <CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>
 <51BEB89A.3090105@ti.com>
 <CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>
 <51BEBDAF.7000201@ti.com>
 <CAD6G_RSog7AJwfJigewGnF8C=Dw3yWv38Q8hR4xaayjmicQXFw@mail.gmail.com>
 <51BECCB6.3030304@ti.com>
Message-ID: <CAD6G_RT4xR2=ehsx1aJMV6aNkj=HaTG5AEGVGQ2NSESBfBcCnQ@mail.gmail.com>

On Mon, Jun 17, 2013 at 2:15 PM, Sourav Poddar <sourav.poddar at ti.com> wrote:
> On Monday 17 June 2013 02:09 PM, Jagan Teki wrote:
>>
>> On Mon, Jun 17, 2013 at 1:11 PM, Sourav Poddar<sourav.poddar at ti.com>
>> wrote:
>>>
>>> Hi Jagan,
>>>
>>> On Monday 17 June 2013 01:04 PM, Jagan Teki wrote:
>>>>
>>>> On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>> wrote:
>>>>>
>>>>> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>>>>>
>>>>>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>>>>>
>>>>>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav
>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> HI Jagan,
>>>>>>>>>
>>>>>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>>>>>
>>>>>>>>>> Hi Sourav,
>>>>>>>>>>
>>>>>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav
>>>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>>
>>>>>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level.
>>>>>>>>>>>>>>>> I
>>>>>>>>>>>>>>>> am
>>>>>>>>>>>>>>>> trying to
>>>>>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>>>>>> u-boot
>>>>>>>>>>>>>>>> for
>>>>>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> There are several issues(mentioned below), which I faced
>>>>>>>>>>>>>>>> while
>>>>>>>>>>>>>>>> using
>>>>>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which
>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>>>>>       - erases only first 0x20000 bytes of flash device,
>>>>>>>>>>>>>>>> anything
>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>>>>>         issue separate commands after 0x20000 for every
>>>>>>>>>>>>>>>> 0x10000
>>>>>>>>>>>>>>>> bytes.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 2. read
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Read is not happening properly. The last few byte along the
>>>>>>>>>>>>>>>> 4k
>>>>>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> For ex:
>>>>>>>>>>>>>>>>       DRA752 EVM # md 81000f00
>>>>>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows
>>>>>>>>>>>>>>>> 000000
>>>>>>>>>>>>>>>> which
>>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read
>>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>>>>>> [1]:
>>>>>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct
>>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>>>>>       int spi_flash_cmd_read_fast(struct spi_flash *flash,
>>>>>>>>>>>>>>>> u32
>>>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>>>                      size_t len, void *data)
>>>>>>>>>>>>>>>>       {
>>>>>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>              /* Handle memory-mapped SPI */
>>>>>>>>>>>>>>>>              if (flash->memory_map)
>>>>>>>>>>>>>>>>                      memcpy(data, flash->memory_map +
>>>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>>>>>> +       for (actual = 0; actual<      len; actual +=
>>>>>>>>>>>>>>>> chunk_len)
>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +               cmd[1] = page_addr>>      8;
>>>>>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>>>>>> +               if (ret<      0) {
>>>>>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>> +       }
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>>>> data,
>>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>>>>>       }
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>>>>>        write not happening properly.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> observations: only able to write single page, anything after
>>>>>>>>>>>>>>>> a
>>>>>>>>>>>>>>>> page
>>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>>> not getting
>>>>>>>>>>>>>>>>              written.
>>>>>>>>>>>>>>>> Workaround:
>>>>>>>>>>>>>>>> I did a write disable latch at the end of every write
>>>>>>>>>>>>>>>> cycle(page
>>>>>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the
>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>> issue.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>       @@ -117,6 +117,12 @@ int
>>>>>>>>>>>>>>>> spi_flash_cmd_write_multi(struct
>>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>>>>>                      if (ret)
>>>>>>>>>>>>>>>>                              break;
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>>>>>> +               if (ret<      0) {
>>>>>>>>>>>>>>>> +                       printf("SF: disabling write
>>>>>>>>>>>>>>>> failed\n");
>>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Any Input on this?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> We will continue this thread, after testing your part with
>>>>>>>>>>>>>> these
>>>>>>>>>>>>>> new
>>>>>>>>>>>>>> changes.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> --
>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>> Jagan.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Will take some time go these changes on master.
>>>>>>>>>>>>
>>>>>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>>>>>
>>>>>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>>>>>> +ve result.
>>>>>>>>>>>>
>>>>>>>>>>> Tested the above tree on my board.
>>>>>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>>>>>> cases(erase/read/write).
>>>>>>>>>>>
>>>>>>>>>>> Here is the short log of the read command..
>>>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Erase: not able to do with a single command, need to issue for
>>>>>>>>>>> every
>>>>>>>>>>> 0x10000
>>>>>>>>>>> bytes.
>>>>>>>>>>>
>>>>>>>>>>> Write: Need to disable latch after every write to make it
>>>>>>>>>>> properly
>>>>>>>>>>> work.
>>>>>>>>>>>
>>>>>>>>>>> Is it possible for you to  give me  basic commands which you
>>>>>>>>>>> might
>>>>>>>>>>> have
>>>>>>>>>>> ran
>>>>>>>>>>> to confirm
>>>>>>>>>>> the read/write and erase ??
>>>>>>>>>>
>>>>>>>>>> I tested the same part - for me i couldn't see the issues with
>>>>>>>>>> SL256S
>>>>>>>>>>
>>>>>>>>>> OK! can enable the log on poll function,
>>>>>>>>>> spi_flash_cmd_wait_ready()
>>>>>>>>>> make debug ->      printf.
>>>>>>>>>> Do the same test.! and send the log file.
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Thanks,
>>>>>>>>>> Jagan.
>>>>>>>>>
>>>>>>>>> Here is the output log, no change..
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>> DRA752 EVM #
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Code change: for above output.
>>>>>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>>> *flash,
>>>>>>>>> unsigned long timeout)
>>>>>>>>>
>>>>>>>>>             ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>>>>>
>>>>>>>>>             if (ret) {This is still not sent out for review. I can
>>>>>>>>> send you the patch -               debug("SF: fail to read %s
>>>>>>>>> status
>>>>>>>>> register\n",
>>>>>>>>>
>>>>>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>>>>>                             cmd == CMD_READ_STATUS ? "read" :
>>>>>>>>> "flag");
>>>>>>>>>                     return ret;
>>>>>>>>>             }
>>>>>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>>> *flash,
>>>>>>>>> unsigned long timeout)
>>>>>>>>>                     return 0;
>>>>>>>>>
>>>>>>>>>             /* Timed out */
>>>>>>>>> -       debug("SF: time out!\n");
>>>>>>>>> +       printf("SF: time out!\n");
>>>>>>>>>             return -1;
>>>>>>>>>      }
>>>>>>>>>
>>>>>>>> Ohh..
>>>>>>>>
>>>>>>>> - What if you erase the entire flash and read back, same result is
>>>>>>>> it?
>>>>>>>
>>>>>>> Yes.
>>>>>>>
>>>>>>>> - please send the paths for config file for this board?
>>>>>>>
>>>>>>> include/configs/dra7xx_evm.h
>>>>>>
>>>>>> I couldn't find any SPI flash configs on above config file,
>>>>>> Can you point me the relevant configurations.
>>>>>>
>>>>> Following are the configuration details for spi..
>>>>> #define CONFIG_SPI_FLASH_BAR
>>>>> #define CONFIG_TI_QSPI
>>>>
>>>> Where can i find this?
>>>>
>>> I have attached the required patches in the thread.
>>> Patch 0002 is my ti qspi controller.
>>> Patch 0004 is my workarounds done for the all the issues
>>> mentioned in the $subject patch.
>>> Patch 0001 and 0002 are other configs.
>>>
>>>>> #define CONFIG_SPI_FLASH
>>>>> #define CONFIG_SPI_FLASH_SPANSION
>>>>> #define CONFIG_CMD_SF
>>>>> #define CONFIG_CMD_SPI
>>>>> #define CONFIG_SF_DEFAULT_SPEED         12000000
>>>>> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>>>>>
>>>>> /* SPI SPL */
>>>>> #define CONFIG_SPL_SPI_SUPPORT
>>>>> #define CONFIG_SPL_SPI_LOAD
>>>>> #define CONFIG_SPL_SPI_FLASH_SUPPORT
>>>>> #define CONFIG_SPL_SPI_BUS              0
>>>>> #define CONFIG_SPL_SPI_CS               0
>>>>> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000
>>
>> Ohh... these drivers not yet in mainline.Ok?
>>
> They are not in mainline, yet. Due to above mentioned issue, I have not
>  posted it yet.
>
>> Did you ever tested any of other flash parts (other 256S) with these
>> drivers.
>> Let me give some time to go through these drivers code.
>>
> No, I don,t have any other board which has any other flash device.

Did you confirm, there is no hw/board issues with this flash.
because I have tested the same part on xilinx zynq soc, zed board, i
couldn't see any issues.

>
>> Do you confident that ti_qspi.c doesn't have any issues while
>> processing SPI transactions.?
>>
> I tried putting a lot of prints, which does not show any obvious error.
I am not sure, the logic behind ti_omap.c
but might be some SPI transaction handling on controller for ever 0x1000 bytes.
Need to see.

>
> Moreover, with the workaround mentioned before, things work fine.
No, that work around is against the flash read concept, generally
flash read not in-terms of page sizes but your workaround does.

Need to digging more on 0x1000bytes - I am come back with any clue
means while I am also start looking your controller driver.
Can you send your trm link, does it available on web.

--
Thanks,
Jagan.


From sourav.poddar at ti.com  Mon Jun 17 06:20:53 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Mon, 17 Jun 2013 15:50:53 +0530
Subject: [U-Boot] U-boot: Erase/read/write issue with S25fl256S flash
 device
In-Reply-To: <CAD6G_RT4xR2=ehsx1aJMV6aNkj=HaTG5AEGVGQ2NSESBfBcCnQ@mail.gmail.com>
References: <51B82388.2000909@ti.com>	<51BB29A5.3000100@ti.com>	<51BB2AE4.4020109@gmail.com>	<51BB2C2B.1010404@ti.com>	<51BC93AF.5080808@gmail.com>	<51BEA955.9080907@ti.com>	<CAD6G_RTUSPgUf0GMeXDxkmTKmjx-_YaV6TR4_kGz0Zm_2SpxQw@mail.gmail.com>	<51BEB3AB.6020603@ti.com>	<CAD6G_RQPfQrwxkYZvB+hx6YVrMSNNYKSzCEB9_8t0SYCfwKt2g@mail.gmail.com>	<51BEB69B.5010902@ti.com>	<CAD6G_RSXJ-k0ciwc8zdKwimAnLwCv=9YTv4YkmAqrREizEtDUg@mail.gmail.com>	<51BEB89A.3090105@ti.com>	<CAD6G_RRNT5ukFovS1Spa7uMmX72kLpZ-YycfcdDdESTMHnNU9Q@mail.gmail.com>	<51BEBDAF.7000201@ti.com>	<CAD6G_RSog7AJwfJigewGnF8C=Dw3yWv38Q8hR4xaayjmicQXFw@mail.gmail.com>	<51BECCB6.3030304@ti.com>
 <CAD6G_RT4xR2=ehsx1aJMV6aNkj=HaTG5AEGVGQ2NSESBfBcCnQ@mail.gmail.com>
Message-ID: <51BEE305.9030708@ti.com>

On Monday 17 June 2013 03:28 PM, Jagan Teki wrote:
> On Mon, Jun 17, 2013 at 2:15 PM, Sourav Poddar<sourav.poddar at ti.com>  wrote:
>> On Monday 17 June 2013 02:09 PM, Jagan Teki wrote:
>>> On Mon, Jun 17, 2013 at 1:11 PM, Sourav Poddar<sourav.poddar at ti.com>
>>> wrote:
>>>> Hi Jagan,
>>>>
>>>> On Monday 17 June 2013 01:04 PM, Jagan Teki wrote:
>>>>> On Mon, Jun 17, 2013 at 12:49 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>> wrote:
>>>>>> On Monday 17 June 2013 12:44 PM, Jagan Teki wrote:
>>>>>>> On Mon, Jun 17, 2013 at 12:41 PM, Sourav Poddar<sourav.poddar at ti.com>
>>>>>>> wrote:
>>>>>>>> On Monday 17 June 2013 12:35 PM, Jagan Teki wrote:
>>>>>>>>> On Mon, Jun 17, 2013 at 12:28 PM, Sourav
>>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>>> wrote:
>>>>>>>>>> HI Jagan,
>>>>>>>>>>
>>>>>>>>>> On Monday 17 June 2013 12:17 PM, Jagan Teki wrote:
>>>>>>>>>>> Hi Sourav,
>>>>>>>>>>>
>>>>>>>>>>> On Mon, Jun 17, 2013 at 11:44 AM, Sourav
>>>>>>>>>>> Poddar<sourav.poddar at ti.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>>>
>>>>>>>>>>>> On Saturday 15 June 2013 09:47 PM, Jagan Teki wrote:
>>>>>>>>>>>>> On 14-06-2013 20:13, Sourav Poddar wrote:
>>>>>>>>>>>>>> Hi Jagan,
>>>>>>>>>>>>>> On Friday 14 June 2013 08:08 PM, Jagan Teki wrote:
>>>>>>>>>>>>>>> On 14-06-2013 20:03, Sourav Poddar wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Wednesday 12 June 2013 01:00 PM, Sourav Poddar wrote:
>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I am working on qspi flash device S25FL256S at u-boot level.
>>>>>>>>>>>>>>>>> I
>>>>>>>>>>>>>>>>> am
>>>>>>>>>>>>>>>>> trying to
>>>>>>>>>>>>>>>>> make use of the existing spi_flash.c framework available at
>>>>>>>>>>>>>>>>> u-boot
>>>>>>>>>>>>>>>>> for
>>>>>>>>>>>>>>>>> erasing/reading/writing
>>>>>>>>>>>>>>>>> into the flash device.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> There are several issues(mentioned below), which I faced
>>>>>>>>>>>>>>>>> while
>>>>>>>>>>>>>>>>> using
>>>>>>>>>>>>>>>>> S25FL256s flash device
>>>>>>>>>>>>>>>>> with my dra7xx board which has a qspi controller to which
>>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>>> mentioned flash device is attached.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> 1. Erase (spi_flash_cmd_erase)
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Issuing a command something like this..
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> sf erase 0x0 0x50000
>>>>>>>>>>>>>>>>>        - erases only first 0x20000 bytes of flash device,
>>>>>>>>>>>>>>>>> anything
>>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>>> that is not erase. I need to
>>>>>>>>>>>>>>>>>          issue separate commands after 0x20000 for every
>>>>>>>>>>>>>>>>> 0x10000
>>>>>>>>>>>>>>>>> bytes.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Am i missing anything here?
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> 2. read
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> sf read 81000000 0 0x10000
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Read is not happening properly. The last few byte along the
>>>>>>>>>>>>>>>>> 4k
>>>>>>>>>>>>>>>>> boundary always shows zero.
>>>>>>>>>>>>>>>>> Above 4k bytes, read is not happening.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> For ex:
>>>>>>>>>>>>>>>>>        DRA752 EVM # md 81000f00
>>>>>>>>>>>>>>>>> 81000f00: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f10: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f20: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f30: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f40: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f50: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f60: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f70: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f80: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000f90: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000fa0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000fb0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000fc0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000fd0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000fe0: ffffffff ffffffff ffffffff ffffffff
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>> 81000ff0: ffffffff ffffffff 00ffffff 00000000
>>>>>>>>>>>>>>>>> ................
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> In this dump, if you see 81000ff0 the last column shows
>>>>>>>>>>>>>>>>> 000000
>>>>>>>>>>>>>>>>> which
>>>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>>>> not expected. and it happens along every 4k bytes.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> So, to get rid of the above issue, I switched to page read
>>>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>> below patch[1],
>>>>>>>>>>>>>>>>> which is giving me the correct result.
>>>>>>>>>>>>>>>>> [1]:
>>>>>>>>>>>>>>>>> @@ -147,17 +153,40 @@ int spi_flash_read_common(struct
>>>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>>>> *flash, const u8 *cmd,
>>>>>>>>>>>>>>>>>        int spi_flash_cmd_read_fast(struct spi_flash *flash,
>>>>>>>>>>>>>>>>> u32
>>>>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>>>>                       size_t len, void *data)
>>>>>>>>>>>>>>>>>        {
>>>>>>>>>>>>>>>>> -       u8 cmd[5];
>>>>>>>>>>>>>>>>> +       unsigned long page_addr, byte_addr, page_size;
>>>>>>>>>>>>>>>>> +       size_t chunk_len, actual;
>>>>>>>>>>>>>>>>> +       int ret = 0;
>>>>>>>>>>>>>>>>> +       u8 cmd[4];
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>               /* Handle memory-mapped SPI */
>>>>>>>>>>>>>>>>>               if (flash->memory_map)
>>>>>>>>>>>>>>>>>                       memcpy(data, flash->memory_map +
>>>>>>>>>>>>>>>>> offset,
>>>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>>>> +       page_size = flash->page_size;
>>>>>>>>>>>>>>>>> +       page_addr = offset / page_size;
>>>>>>>>>>>>>>>>> +       byte_addr = offset % page_size;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +       cmd[0] = CMD_READ_ARRAY_SLOW;
>>>>>>>>>>>>>>>>> +       for (actual = 0; actual<       len; actual +=
>>>>>>>>>>>>>>>>> chunk_len)
>>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>>> +               chunk_len = min(len - actual, page_size -
>>>>>>>>>>>>>>>>> byte_addr);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +               cmd[1] = page_addr>>       8;
>>>>>>>>>>>>>>>>> +               cmd[2] = page_addr;
>>>>>>>>>>>>>>>>> +               cmd[3] = byte_addr;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +               ret = spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>>>>> data + actual, chunk_len);
>>>>>>>>>>>>>>>>> +               if (ret<       0) {
>>>>>>>>>>>>>>>>> +                       debug("SF: read failed");
>>>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> -       cmd[0] = CMD_READ_ARRAY_FAST;
>>>>>>>>>>>>>>>>> -       spi_flash_addr(offset, cmd);
>>>>>>>>>>>>>>>>> -       cmd[4] = 0x00;
>>>>>>>>>>>>>>>>> +               byte_addr += chunk_len;
>>>>>>>>>>>>>>>>> +               if (byte_addr == page_size) {
>>>>>>>>>>>>>>>>> +                       page_addr++;
>>>>>>>>>>>>>>>>> +                       byte_addr = 0;
>>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>>> +       }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> -       return spi_flash_read_common(flash, cmd,
>>>>>>>>>>>>>>>>> sizeof(cmd),
>>>>>>>>>>>>>>>>> data,
>>>>>>>>>>>>>>>>> len);
>>>>>>>>>>>>>>>>> +       return ret;
>>>>>>>>>>>>>>>>>        }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Any idea about this?
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> 3.  write (spi_flash_cmd_write_multi)
>>>>>>>>>>>>>>>>>         write not happening properly.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> observations: only able to write single page, anything after
>>>>>>>>>>>>>>>>> a
>>>>>>>>>>>>>>>>> page
>>>>>>>>>>>>>>>>> is
>>>>>>>>>>>>>>>>> not getting
>>>>>>>>>>>>>>>>>               written.
>>>>>>>>>>>>>>>>> Workaround:
>>>>>>>>>>>>>>>>> I did a write disable latch at the end of every write
>>>>>>>>>>>>>>>>> cycle(page
>>>>>>>>>>>>>>>>> program) and enable it
>>>>>>>>>>>>>>>>> again for the next loop. With this, I see I get rid of the
>>>>>>>>>>>>>>>>> above
>>>>>>>>>>>>>>>>> issue.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>        @@ -117,6 +117,12 @@ int
>>>>>>>>>>>>>>>>> spi_flash_cmd_write_multi(struct
>>>>>>>>>>>>>>>>> spi_flash
>>>>>>>>>>>>>>>>> *flash, u32 offset,
>>>>>>>>>>>>>>>>>                       if (ret)
>>>>>>>>>>>>>>>>>                               break;
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> +               ret = spi_flash_cmd_write_disable(flash);
>>>>>>>>>>>>>>>>> +               if (ret<       0) {
>>>>>>>>>>>>>>>>> +                       printf("SF: disabling write
>>>>>>>>>>>>>>>>> failed\n");
>>>>>>>>>>>>>>>>> +                       break;
>>>>>>>>>>>>>>>>> +               }
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Have anyone seen the above mentioned issues regarding
>>>>>>>>>>>>>>>>> read/write/erase? OR is there any
>>>>>>>>>>>>>>>>> configurations that I might be missing ?
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Any Input on this?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Please wait, I am pushing some changes tonight or so.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> We will continue this thread, after testing your part with
>>>>>>>>>>>>>>> these
>>>>>>>>>>>>>>> new
>>>>>>>>>>>>>>> changes.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I will intimate you once the push done.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>> Jagan.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks a lot for the reply.
>>>>>>>>>>>>>> Sure, will wait for your changes to go in.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Will take some time go these changes on master.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Please checkout master-work branch in u-boot-spi repo
>>>>>>>>>>>>> git://git.denx.de/u-boot-spi.git
>>>>>>>>>>>>>
>>>>>>>>>>>>> and try to test 256S parts, fyi: I tested the same part got the
>>>>>>>>>>>>> +ve result.
>>>>>>>>>>>>>
>>>>>>>>>>>> Tested the above tree on my board.
>>>>>>>>>>>> But, still the issues remain the same for me in all the three
>>>>>>>>>>>> cases(erase/read/write).
>>>>>>>>>>>>
>>>>>>>>>>>> Here is the short log of the read command..
>>>>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>>>>> SF: Warning - Only lower 16MiB accessible, Full access #define
>>>>>>>>>>>> CONFIG_SPI_FLASH_BAR
>>>>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Erase: not able to do with a single command, need to issue for
>>>>>>>>>>>> every
>>>>>>>>>>>> 0x10000
>>>>>>>>>>>> bytes.
>>>>>>>>>>>>
>>>>>>>>>>>> Write: Need to disable latch after every write to make it
>>>>>>>>>>>> properly
>>>>>>>>>>>> work.
>>>>>>>>>>>>
>>>>>>>>>>>> Is it possible for you to  give me  basic commands which you
>>>>>>>>>>>> might
>>>>>>>>>>>> have
>>>>>>>>>>>> ran
>>>>>>>>>>>> to confirm
>>>>>>>>>>>> the read/write and erase ??
>>>>>>>>>>> I tested the same part - for me i couldn't see the issues with
>>>>>>>>>>> SL256S
>>>>>>>>>>>
>>>>>>>>>>> OK! can enable the log on poll function,
>>>>>>>>>>> spi_flash_cmd_wait_ready()
>>>>>>>>>>> make debug ->       printf.
>>>>>>>>>>> Do the same test.! and send the log file.
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Jagan.
>>>>>>>>>> Here is the output log, no change..
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> DRA752 EVM # sf probe 0
>>>>>>>>>> SF: Detected S25FL256S_64K with page size 64 KiB, total 32 MiB
>>>>>>>>>> DRA752 EVM # sf erase 0x0 0x10000
>>>>>>>>>> SF: 65536 bytes @ 0x0 Erased: OK
>>>>>>>>>> DRA752 EVM # mw.b 0x81000100 0xff 0x10000
>>>>>>>>>> DRA752 EVM # sf read 0x81003000 0x0 0x10000
>>>>>>>>>> SF: 65536 bytes @ 0x0 Read: OK
>>>>>>>>>> DRA752 EVM # cmp.b 0x81003000  0x81000100  0x10000
>>>>>>>>>> byte at 0x81003ffb (0x0) != byte at 0x810010fb (0xff)
>>>>>>>>>> Total of 4091 byte(s) were the same
>>>>>>>>>> DRA752 EVM #
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Code change: for above output.
>>>>>>>>>> --- a/drivers/mtd/spi/spi_flash.c
>>>>>>>>>> +++ b/drivers/mtd/spi/spi_flash.c
>>>>>>>>>> @@ -85,7 +85,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>>>> *flash,
>>>>>>>>>> unsigned long timeout)
>>>>>>>>>>
>>>>>>>>>>              ret = spi_xfer(spi, 8,&cmd, NULL, SPI_XFER_BEGIN);
>>>>>>>>>>
>>>>>>>>>>              if (ret) {This is still not sent out for review. I can
>>>>>>>>>> send you the patch -               debug("SF: fail to read %s
>>>>>>>>>> status
>>>>>>>>>> register\n",
>>>>>>>>>>
>>>>>>>>>> +               printf("SF: fail to read %s status register\n",
>>>>>>>>>>                              cmd == CMD_READ_STATUS ? "read" :
>>>>>>>>>> "flag");
>>>>>>>>>>                      return ret;
>>>>>>>>>>              }
>>>>>>>>>> @@ -109,7 +109,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash
>>>>>>>>>> *flash,
>>>>>>>>>> unsigned long timeout)
>>>>>>>>>>                      return 0;
>>>>>>>>>>
>>>>>>>>>>              /* Timed out */
>>>>>>>>>> -       debug("SF: time out!\n");
>>>>>>>>>> +       printf("SF: time out!\n");
>>>>>>>>>>              return -1;
>>>>>>>>>>       }
>>>>>>>>>>
>>>>>>>>> Ohh..
>>>>>>>>>
>>>>>>>>> - What if you erase the entire flash and read back, same result is
>>>>>>>>> it?
>>>>>>>> Yes.
>>>>>>>>
>>>>>>>>> - please send the paths for config file for this board?
>>>>>>>> include/configs/dra7xx_evm.h
>>>>>>> I couldn't find any SPI flash configs on above config file,
>>>>>>> Can you point me the relevant configurations.
>>>>>>>
>>>>>> Following are the configuration details for spi..
>>>>>> #define CONFIG_SPI_FLASH_BAR
>>>>>> #define CONFIG_TI_QSPI
>>>>> Where can i find this?
>>>>>
>>>> I have attached the required patches in the thread.
>>>> Patch 0002 is my ti qspi controller.
>>>> Patch 0004 is my workarounds done for the all the issues
>>>> mentioned in the $subject patch.
>>>> Patch 0001 and 0002 are other configs.
>>>>
>>>>>> #define CONFIG_SPI_FLASH
>>>>>> #define CONFIG_SPI_FLASH_SPANSION
>>>>>> #define CONFIG_CMD_SF
>>>>>> #define CONFIG_CMD_SPI
>>>>>> #define CONFIG_SF_DEFAULT_SPEED         12000000
>>>>>> #define CONFIG_DEFAULT_SPI_MODE         SPI_MODE_3
>>>>>>
>>>>>> /* SPI SPL */
>>>>>> #define CONFIG_SPL_SPI_SUPPORT
>>>>>> #define CONFIG_SPL_SPI_LOAD
>>>>>> #define CONFIG_SPL_SPI_FLASH_SUPPORT
>>>>>> #define CONFIG_SPL_SPI_BUS              0
>>>>>> #define CONFIG_SPL_SPI_CS               0
>>>>>> #define CONFIG_SYS_SPI_U_BOOT_OFFS      0x20000
>>> Ohh... these drivers not yet in mainline.Ok?
>>>
>> They are not in mainline, yet. Due to above mentioned issue, I have not
>>   posted it yet.
>>
>>> Did you ever tested any of other flash parts (other 256S) with these
>>> drivers.
>>> Let me give some time to go through these drivers code.
>>>
>> No, I don,t have any other board which has any other flash device.
> Did you confirm, there is no hw/board issues with this flash.
> because I have tested the same part on xilinx zynq soc, zed board, i
> couldn't see any issues.
>
Yes, since the same board is used by BIOS/QNX people to validate the
flash using their driver.
>>> Do you confident that ti_qspi.c doesn't have any issues while
>>> processing SPI transactions.?
>>>
>> I tried putting a lot of prints, which does not show any obvious error.
> I am not sure, the logic behind ti_omap.c
> but might be some SPI transaction handling on controller for ever 0x1000 bytes.
> Need to see.
>
>> Moreover, with the workaround mentioned before, things work fine.
> No, that work around is against the flash read concept, generally
> flash read not in-terms of page sizes but your workaround does.
>
Yes, I know, thats the whoile reason I have not posted my patches still.
> Need to digging more on 0x1000bytes - I am come back with any clue
> means while I am also start looking your controller driver.
> Can you send your trm link, does it available on web.
>
Its public version is not available yet, so I cant.

Is it possible for you to send me the output of following commands on 
your board?

sf erase 0 80000
sf read 81000000 0 80000
md 81000000
md 81030000

mw 84000000 aaaaaaaa 10000
sf write 84000000 0 10000
sf read 81000000 0 10000
md 81000000
md 81002000

~Sourav
> --
> Thanks,
> Jagan.



From ezequiel.garcia at free-electrons.com  Mon Jun 17 07:03:05 2013
From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia)
Date: Mon, 17 Jun 2013 08:03:05 -0300
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <51BEA455.2020605@compulab.co.il>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <51BEA455.2020605@compulab.co.il>
Message-ID: <20130617110304.GA2624@localhost>

Nikita, Igor:

On Mon, Jun 17, 2013 at 08:53:25AM +0300, Igor Grinberg wrote:
> On 05/14/13 14:15, Ezequiel Garcia wrote:
> > The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
> > is similar to the one in PXA SoC. Therefore, it should be possible to support
> > Armada NAND using pxa3xx-nand driver.
> > 
> > While this effort is not ready yet, here is a set of patches that are needed
> > for such work.
> > 
> > A small summary of the patches:
> > 
> >   * 1/5 is a fix for a 2-year regression that removed DMA support.
> > 
> >   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
> > 
> >   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
> >     to successfully probe newer flash devices.
> > 
> > Applies cleanly on top of l2-mtd.git.
> > 
> > Thanks!
> > 
> > Ezequiel Garcia (5):
> >   mtd: nand: pxa3xx: Set info->use_dma properly
> >   mtd: nand: pxa3xx: Use of_machine_is_compatible()
> >   mtd: nand: pxa3xx: Fix MODULE_DEVICE_TABLE declaration
> >   mtd: nand: pxa3xx: Add address support for READID command
> >   mtd: nand: pxa3xx: Add support for Read parameter page command
> 
> tested on cm-x300, upstream 3.10-rc5 and no regressions seen.
> 
> Tested-by: Nikita Kiryanov <nikita at compulab.co.il>
> Acked-by: Igor Grinberg <grinberg at compulab.co.il>
> 

Thanks a lot for the review and the test!

Artem, do you think this could be queued for v3.11?

-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com


From Anton.Prins at nl.bosch.com  Mon Jun 17 07:20:49 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Mon, 17 Jun 2013 13:20:49 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F41650D@SI-MBX14.de.bosch.com>

Thanks Mats for your information; hopefully the 'double free' patches will solve something!

Over here we did run a test over the weekend with 70 devices and the logging as mentioned in previous messages.
(without the 'double free' patches mentioned earlier, this to be able to point to a root-cause). 
Next to the logging we did binary analyze LEB9.

The results is that the 70 devices in total had 88 writes to the orphan area of node 0.. (ranging from 0 to 5 node 0 writes on a single device).
We also analyzed the 70 LEB9s which gave the same total of 88 node 0's inside them.

These writes of node 0 did not turn in a reboot-failure or any other problem; 
So I expect a second scenario where node 1 is written, but not yet seen in any logging up to now!

Adrian, when will de orphan area be 'cleaned'? 
May I analyze it after reboot/recovery as well?

Now we know about our logging of 'node 0'; we will apply the patches and check the log-results in this case.
A subset of our devices; I will keep in the old-scenario to test for node-1 logging (and reboot failures)

Adrian, could there be a way to trigger the problem that the 'double free' patch solves, more often?

Thanks in Advance,

Anton





From pekon at ti.com  Mon Jun 17 14:46:38 2013
From: pekon at ti.com (Pekon Gupta)
Date: Tue, 18 Jun 2013 00:16:38 +0530
Subject: [PATCH v5 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371494799-11876-1-git-send-email-pekon@ti.com>
References: <1371494799-11876-1-git-send-email-pekon@ti.com>
Message-ID: <1371494799-11876-3-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

GPMC is hardware controller for external memory interfaces.
This patch adds suspend/resume support for GPMC driver.
It also preserves GPMC register configurations across device low-power states
in which GPMC hardware can be powered-off.
gpmc_suspend()/gpmc_resume() are called by default by core PM framework as part
of driver's runtime PM callbacks.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1380cee..9b579d0 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1655,6 +1655,24 @@ static int gpmc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpmc_suspend(struct device *dev)
+{
+	omap3_gpmc_save_context();
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int gpmc_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	omap3_gpmc_restore_context();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
+
 static struct platform_driver gpmc_driver = {
 	.probe		= gpmc_probe,
 	.remove		= gpmc_remove,
@@ -1662,6 +1680,7 @@ static struct platform_driver gpmc_driver = {
 		.name	= DEVICE_NAME,
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(gpmc_dt_ids),
+		.pm	= &gpmc_pm_ops,
 	},
 };
 
@@ -1724,7 +1743,6 @@ static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_ARCH_OMAP3
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
@@ -1789,4 +1807,3 @@ void omap3_gpmc_restore_context(void)
 		}
 	}
 }
-#endif /* CONFIG_ARCH_OMAP3 */
-- 
1.8.1



From pekon at ti.com  Mon Jun 17 14:46:36 2013
From: pekon at ti.com (Pekon Gupta)
Date: Tue, 18 Jun 2013 00:16:36 +0530
Subject: [PATCH v5 0/3] suspend/resume support for OMAP nand driver
Message-ID: <1371494799-11876-1-git-send-email-pekon@ti.com>

This patch series adds runtime PM support (specifically suspend/resume) 
for GPMC and ELM drivers.
[Patch 1/3]: Adds pm_runtime calls to handle GPMC module probe and remove
[Patch 2/3]: Adds GPMC suspend/resume support.
[Patch 3/3]: Adds ELM suspend/resume support.

Tested on am335x-evm with NAND flash support, using following:
	echo devices 	> /sys/power/pm_test
	echo mem	> /sys/power/state

	echo core	> /sys/power/pm_test
	echo mem	> /sys/power/state

Changes since v4:
- added save/restore to ELM suspend/resume
- removed #ifdef CONFIG_ARCH_OMAP3
- updated changelog to be more descriptive

Changes Since v3:
- CONFIG_PM -> CONFIG_PM_SLEEP
- using struct dev_pm_ops via driver->pm, instead of struct platform_driver
- rebased to 3.10-rc5

Changes Since v2:
- Remove calll back of nand_suspend from omap2 nand driver, as the same call
  already done from suspend activity mtd class driver.

[1] http://comments.gmane.org/gmane.linux.ports.arm.omap/91405


avinash philip (3):
  ARM: OMAP2+: gpmc: Converts GPMC driver to pm_runtime capable
  arm: gpmc: Low power transition support
  mtd: devices: elm: Low power transition support

 arch/arm/mach-omap2/gpmc.c |  29 +++++++++--
 drivers/mtd/devices/elm.c  | 117 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+), 4 deletions(-)

-- 
1.8.1



From pekon at ti.com  Mon Jun 17 14:46:37 2013
From: pekon at ti.com (Pekon Gupta)
Date: Tue, 18 Jun 2013 00:16:37 +0530
Subject: [PATCH v5 1/3] ARM: OMAP2+: gpmc: Converts GPMC driver to pm_runtime
 capable
In-Reply-To: <1371494799-11876-1-git-send-email-pekon@ti.com>
References: <1371494799-11876-1-git-send-email-pekon@ti.com>
Message-ID: <1371494799-11876-2-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

Support for pm_runtime add to GPMC driver.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
Signed-off-by: Tony Lindgren <tony at atomide.com>
---
 arch/arm/mach-omap2/gpmc.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index fb6f241..1380cee 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -30,6 +30,7 @@
 #include <linux/of_mtd.h>
 #include <linux/of_device.h>
 #include <linux/mtd/nand.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
@@ -1594,7 +1595,8 @@ static int gpmc_probe(struct platform_device *pdev)
 		return PTR_ERR(gpmc_l3_clk);
 	}
 
-	clk_prepare_enable(gpmc_l3_clk);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
 
 	gpmc_dev = &pdev->dev;
 
@@ -1634,7 +1636,7 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	rc = gpmc_probe_dt(pdev);
 	if (rc < 0) {
-		clk_disable_unprepare(gpmc_l3_clk);
+		pm_runtime_put_sync(&pdev->dev);
 		clk_put(gpmc_l3_clk);
 		dev_err(gpmc_dev, "failed to probe DT parameters\n");
 		return rc;
@@ -1647,6 +1649,8 @@ static int gpmc_remove(struct platform_device *pdev)
 {
 	gpmc_free_irq();
 	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 	gpmc_dev = NULL;
 	return 0;
 }
-- 
1.8.1



From pekon at ti.com  Mon Jun 17 14:46:39 2013
From: pekon at ti.com (Pekon Gupta)
Date: Tue, 18 Jun 2013 00:16:39 +0530
Subject: [PATCH v5 3/3] mtd: devices: elm: Low power transition support
In-Reply-To: <1371494799-11876-1-git-send-email-pekon@ti.com>
References: <1371494799-11876-1-git-send-email-pekon@ti.com>
Message-ID: <1371494799-11876-4-git-send-email-pekon@ti.com>

From: avinash philip <avinashphilip at ti.com>

ELM is used for locating bit-flip errors in when using BCH ECC scheme.
This patch adds suspend/resume support for leaf level ELM driver,
And also provides ELM register context save & restore support, so that
configurations are preserved across hardware power-off/on transitions.

Signed-off-by: Philip Avinash <avinashphilip at ti.com>
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 drivers/mtd/devices/elm.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
index dccef9f..e6a7b89 100644
--- a/drivers/mtd/devices/elm.c
+++ b/drivers/mtd/devices/elm.c
@@ -20,14 +20,21 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 
+#define ELM_SYSCONFIG			0x010
 #define ELM_IRQSTATUS			0x018
 #define ELM_IRQENABLE			0x01c
 #define ELM_LOCATION_CONFIG		0x020
 #define ELM_PAGE_CTRL			0x080
 #define ELM_SYNDROME_FRAGMENT_0		0x400
+#define ELM_SYNDROME_FRAGMENT_1		0x404
+#define ELM_SYNDROME_FRAGMENT_2		0x408
+#define ELM_SYNDROME_FRAGMENT_3		0x40c
+#define ELM_SYNDROME_FRAGMENT_4		0x410
+#define ELM_SYNDROME_FRAGMENT_5		0x414
 #define ELM_SYNDROME_FRAGMENT_6		0x418
 #define ELM_LOCATION_STATUS		0x800
 #define ELM_ERROR_LOCATION_0		0x880
@@ -56,12 +63,27 @@
 #define SYNDROME_FRAGMENT_REG_SIZE	0x40
 #define ERROR_LOCATION_SIZE		0x100
 
+struct elm_registers {
+	u32 elm_irqenable;
+	u32 elm_sysconfig;
+	u32 elm_location_config;
+	u32 elm_page_ctrl;
+	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+};
+
 struct elm_info {
 	struct device *dev;
 	void __iomem *elm_base;
 	struct completion elm_completion;
 	struct list_head list;
 	enum bch_ecc bch_type;
+	struct elm_registers elm_regs;
 };
 
 static LIST_HEAD(elm_devices);
@@ -385,6 +407,100 @@ static int elm_remove(struct platform_device *pdev)
 	return 0;
 }
 
+/**
+ * elm_context_save
+ * saves ELM configurations to preserve them across Hardware powered-down
+ */
+static int elm_context_save(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH8_ECC:
+			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_3 + offset);
+			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_2 + offset);
+		case BCH4_ECC:
+			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_1 + offset);
+			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_0 + offset);
+		default:
+			return -EINVAL;
+		}
+		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+		 * to be saved for all BCH schemes*/
+		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_6 + offset);
+	}
+	return 0;
+}
+
+/**
+ * elm_context_restore
+ * writes configurations saved duing power-down back into ELM registers
+ */
+static int elm_context_restore(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
+	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
+	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH8_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+					regs->elm_syndrome_fragment_3[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+					regs->elm_syndrome_fragment_2[i]);
+		case BCH4_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+					regs->elm_syndrome_fragment_1[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+					regs->elm_syndrome_fragment_0[i]);
+		default:
+			return -EINVAL;
+		}
+		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+					regs->elm_syndrome_fragment_6[i] &
+							 ELM_SYNDROME_VALID);
+	}
+	return 0;
+}
+
+static int elm_suspend(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	elm_context_save(info);
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	pm_runtime_get_sync(dev);
+	elm_context_restore(info);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
 	{ .compatible = "ti,am3352-elm" },
@@ -398,6 +514,7 @@ static struct platform_driver elm_driver = {
 		.name	= "elm",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(elm_of_match),
+		.pm	= &elm_pm_ops,
 	},
 	.probe	= elm_probe,
 	.remove	= elm_remove,
-- 
1.8.1



From Anton.Prins at nl.bosch.com  Tue Jun 18 02:31:30 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Tue, 18 Jun 2013 08:31:30 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <20130527121828.GA32625@quack.suse.cz>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBB8D@SI-MBX14.de.bosch.com>
 <1369709828.5446.89.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBD81@SI-MBX14.de.bosch.com>
 <1369727042.5446.112.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CBE33@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>

Last night I did do additional tests with create/remove of files in a while loop on a synchronous mounted UBIFS.
I did NOT get any node 0 or 1 written over this night, but obvious enough I saw some strange node id in the orphan area: 0xdead4ead

0xdead4ead Is known to me as SPINLOCK_MAGIC; but no glue why It is in the orphan area if node number...
Is something known about 0xdead4ead?


From adrian.hunter at intel.com  Tue Jun 18 03:01:12 2013
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Tue, 18 Jun 2013 10:01:12 +0300
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
Message-ID: <51C005B8.3000709@intel.com>

On 18/06/13 09:31, Prins Anton (ST-CO/ENG1.1) wrote:
> Last night I did do additional tests with create/remove of files in a
> while loop on a synchronous mounted UBIFS. I did NOT get any node 0 or 1
> written over this night, but obvious enough I saw some strange node id in
> the orphan area: 0xdead4ead
> 
> 0xdead4ead Is known to me as SPINLOCK_MAGIC; but no glue why It is in the
> orphan area if node number... Is something known about 0xdead4ead?

I am afraid I have not had time to analyze the effects of the double-free
but it is reasonable to assume that UBIFS may be writing an orphan from a
structure that has been freed and therefore re-used by, for example in this
case, a spinlock.


From Anton.Prins at nl.bosch.com  Tue Jun 18 03:17:53 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Tue, 18 Jun 2013 09:17:53 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51C005B8.3000709@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
 <51C005B8.3000709@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F41683D@SI-MBX14.de.bosch.com>

Ok thanks, meanwhile we have applied the 'double free' patches in our nightly build and coming week I hope to have more information on this.

-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: dinsdag 18 juni 2013 9:01
To: Prins Anton (ST-CO/ENG1.1)
Cc: Mats K?rrman; linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: Re: UBIFS failure & stable page writes

On 18/06/13 09:31, Prins Anton (ST-CO/ENG1.1) wrote:
> Last night I did do additional tests with create/remove of files in a
> while loop on a synchronous mounted UBIFS. I did NOT get any node 0 or 1
> written over this night, but obvious enough I saw some strange node id in
> the orphan area: 0xdead4ead
> 
> 0xdead4ead Is known to me as SPINLOCK_MAGIC; but no glue why It is in the
> orphan area if node number... Is something known about 0xdead4ead?

I am afraid I have not had time to analyze the effects of the double-free
but it is reasonable to assume that UBIFS may be writing an orphan from a
structure that has been freed and therefore re-used by, for example in this
case, a spinlock.


From tony at atomide.com  Tue Jun 18 06:50:51 2013
From: tony at atomide.com (Tony Lindgren)
Date: Tue, 18 Jun 2013 03:50:51 -0700
Subject: [PATCH v5 2/3] arm: gpmc: Low power transition support
In-Reply-To: <1371494799-11876-3-git-send-email-pekon@ti.com>
References: <1371494799-11876-1-git-send-email-pekon@ti.com>
 <1371494799-11876-3-git-send-email-pekon@ti.com>
Message-ID: <20130618105051.GM5523@atomide.com>

* Pekon Gupta <pekon at ti.com> [130617 11:52]:
> From: avinash philip <avinashphilip at ti.com>
> 
> GPMC is hardware controller for external memory interfaces.
> This patch adds suspend/resume support for GPMC driver.
> It also preserves GPMC register configurations across device low-power states
> in which GPMC hardware can be powered-off.
> gpmc_suspend()/gpmc_resume() are called by default by core PM framework as part
> of driver's runtime PM callbacks.
> 
> Signed-off-by: Philip Avinash <avinashphilip at ti.com>
> Signed-off-by: Pekon Gupta <pekon at ti.com>

Thanks applying this into omap-for-v3.11/gpmc, patch 1/3 I already
have applied and the MTD change should get merged along with other
MTD patches.

Regards,

Tony

> ---
>  arch/arm/mach-omap2/gpmc.c | 21 +++++++++++++++++++--
>  1 file changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> index 1380cee..9b579d0 100644
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -1655,6 +1655,24 @@ static int gpmc_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int gpmc_suspend(struct device *dev)
> +{
> +	omap3_gpmc_save_context();
> +	pm_runtime_put_sync(dev);
> +	return 0;
> +}
> +
> +static int gpmc_resume(struct device *dev)
> +{
> +	pm_runtime_get_sync(dev);
> +	omap3_gpmc_restore_context();
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
> +
>  static struct platform_driver gpmc_driver = {
>  	.probe		= gpmc_probe,
>  	.remove		= gpmc_remove,
> @@ -1662,6 +1680,7 @@ static struct platform_driver gpmc_driver = {
>  		.name	= DEVICE_NAME,
>  		.owner	= THIS_MODULE,
>  		.of_match_table = of_match_ptr(gpmc_dt_ids),
> +		.pm	= &gpmc_pm_ops,
>  	},
>  };
>  
> @@ -1724,7 +1743,6 @@ static irqreturn_t gpmc_handle_irq(int irq, void *dev)
>  	return IRQ_HANDLED;
>  }
>  
> -#ifdef CONFIG_ARCH_OMAP3
>  static struct omap3_gpmc_regs gpmc_context;
>  
>  void omap3_gpmc_save_context(void)
> @@ -1789,4 +1807,3 @@ void omap3_gpmc_restore_context(void)
>  		}
>  	}
>  }
> -#endif /* CONFIG_ARCH_OMAP3 */
> -- 
> 1.8.1
> 


From vincenzo.aliberti at gmail.com  Tue Jun 18 18:39:33 2013
From: vincenzo.aliberti at gmail.com (Vincenzo Aliberti)
Date: Wed, 19 Jun 2013 00:39:33 +0200
Subject: [PATCH] [MTD] MTD driver for LPDDR2-NVM PCM memories
In-Reply-To: <1349385434-3073-1-git-send-email-valibert@micron.com>
References: <1349385434-3073-1-git-send-email-valibert@micron.com>
Message-ID: <CADBu1QvPr_HUz2tRDkDhvhiXtkoNrK9vsaw7T0awk4a12_i+Ug@mail.gmail.com>

On Thu, Oct 4, 2012 at 11:17 PM, Vincenzo Aliberti
<vincenzo.aliberti at gmail.com> wrote:
>
> Dear All,
>     continuing Micron support activity on PCM memories you can find
> here-below a
> patch containing MTD driver for LPDDR2-NVM memories as demoed during Q2
> Linaro
> Connect in Hong Kong.
>
> Let me thank TI Panda open source team for support on platform enablement
> activity and Arnd for his first feedback on driver implementation
>
> Regards,
>         Vincenzo
>
>
> Signed-off-by: Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
> ---
>  drivers/mtd/Kconfig                 |    2 +
>  drivers/mtd/Makefile                |    2 +-
>  drivers/mtd/lpddr2_nvm/Kconfig      |    9 +
>  drivers/mtd/lpddr2_nvm/Makefile     |    5 +
>  drivers/mtd/lpddr2_nvm/lpddr2_nvm.c |  547
> +++++++++++++++++++++++++++++++++++
>  include/mtd/mtd-abi.h               |    1 +
>  6 files changed, 565 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mtd/lpddr2_nvm/Kconfig
>  create mode 100644 drivers/mtd/lpddr2_nvm/Makefile
>  create mode 100644 drivers/mtd/lpddr2_nvm/lpddr2_nvm.c
>
> diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
> index 27143e0..be277b9 100644
> --- a/drivers/mtd/Kconfig
> +++ b/drivers/mtd/Kconfig
> @@ -326,6 +326,8 @@ source "drivers/mtd/onenand/Kconfig"
>
>  source "drivers/mtd/lpddr/Kconfig"
>
> +source "drivers/mtd/lpddr2_nvm/Kconfig"
> +
>  source "drivers/mtd/ubi/Kconfig"
>
>  endif # MTD
> diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
> index f901354..783310e 100644
> --- a/drivers/mtd/Makefile
> +++ b/drivers/mtd/Makefile
> @@ -30,6 +30,6 @@ obj-$(CONFIG_MTD_SWAP)                += mtdswap.o
>  nftl-objs              := nftlcore.o nftlmount.o
>  inftl-objs             := inftlcore.o inftlmount.o
>
> -obj-y          += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
> +obj-y          += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
> lpddr2_nvm/
>
>  obj-$(CONFIG_MTD_UBI)          += ubi/
> diff --git a/drivers/mtd/lpddr2_nvm/Kconfig
> b/drivers/mtd/lpddr2_nvm/Kconfig
> new file mode 100644
> index 0000000..a5cec65
> --- /dev/null
> +++ b/drivers/mtd/lpddr2_nvm/Kconfig
> @@ -0,0 +1,9 @@
> +menu "LPDDR2_NVM memory drivers"
> +       depends on MTD!=n
> +
> +config MTD_LPDDR2_NVM
> +       tristate "Support for LPDDR2-NVM PCM memories"
> +       help
> +         This option enables support of LPDDR2-NVM (Low power double data
> rate 2)
> +         PCM memories.
> +endmenu
> diff --git a/drivers/mtd/lpddr2_nvm/Makefile
> b/drivers/mtd/lpddr2_nvm/Makefile
> new file mode 100644
> index 0000000..dc6fe27
> --- /dev/null
> +++ b/drivers/mtd/lpddr2_nvm/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# linux/drivers/mtd/lpddr2_nvm/Makefile
> +#
> +
> +obj-$(CONFIG_MTD_LPDDR2_NVM)   += lpddr2_nvm.o
> diff --git a/drivers/mtd/lpddr2_nvm/lpddr2_nvm.c
> b/drivers/mtd/lpddr2_nvm/lpddr2_nvm.c
> new file mode 100644
> index 0000000..9c97a9e
> --- /dev/null
> +++ b/drivers/mtd/lpddr2_nvm/lpddr2_nvm.c
> @@ -0,0 +1,547 @@
> +/*
> + * LPDDR2-NVM MTD driver. This module provides read, write, erase,
> lock/unlock
> + * support for LPDDR2-NVM PCM memories
> + *
> + * Copyright ? 2012 Micron Technology, Inc.
> + *
> + * Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
> + * Domenico Manna <domenico.manna at gmail.com>
> + * Many thanks to Andrea Vigilante for intial enabling
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/mtd/map.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/ioport.h>
> +#include <linux/sched.h>
> +
> +/* Parameters */
> +#define ERASE_BLOCKSIZE                        (0x00020000/2)  /* in Word
> */
> +#define WRITE_BUFFSIZE                 (0x00000400/2)  /* in Word */
> +#define OW_BASE_ADDRESS                        0x00000000      /* OW
> offset */
> +
> +/* PFOW symbols address offset */
> +#define PFOW_QUERY_STRING_P            (0x0000/2)      /* in Word */
> +#define PFOW_QUERY_STRING_F            (0x0002/2)      /* in Word */
> +#define PFOW_QUERY_STRING_O            (0x0004/2)      /* in Word */
> +#define PFOW_QUERY_STRING_W            (0x0006/2)      /* in Word */
> +
> +/* OW registers address */
> +#define CMD_CODE_OFS                   (0x0080/2)      /* in Word */
> +#define CMD_DATA_OFS                   (0x0084/2)      /* in Word */
> +#define CMD_ADD_L_OFS                  (0x0088/2)      /* in Word */
> +#define CMD_ADD_H_OFS                  (0x008A/2)      /* in Word */
> +#define MPR_L_OFS                      (0x0090/2)      /* in Word */
> +#define MPR_H_OFS                      (0x0092/2)      /* in Word */
> +#define CMD_EXEC_OFS                   (0x00C0/2)      /* in Word */
> +#define STATUS_REG_OFS                 (0x00CC/2)      /* in Word */
> +#define PRG_BUFFER_OFS                 (0x0010/2)      /* in Word */
> +
> +/* Datamask */
> +#define MR_CFGMASK                     0x8000
> +#define SR_OK_DATAMASK                 0x0080
> +
> +/* LPDDR2-NVM Commands */
> +#define LPDDR2_NVM_LOCK                        0x0061
> +#define LPDDR2_NVM_UNLOCK              0x0062
> +#define LPDDR2_NVM_SW_PROGRAM          0x0041
> +#define LPDDR2_NVM_SW_OVERWRITE                0x0042
> +#define LPDDR2_NVM_BUF_PROGRAM         0x00E9
> +#define LPDDR2_NVM_BUF_OVERWRITE       0x00EA
> +#define LPDDR2_NVM_ERASE               0x0020
> +
> +/*
> + * Internal Type Definitions
> + * pcm_int_data contains memory controller details:
> + * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
> + * @reg_cfg  : LPDDR2_MODE_REG_CFG register address after remapping
> + * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)
> + */
> +struct pcm_int_data {
> +       void __iomem *reg_data;
> +       void __iomem *reg_cfg;
> +       int bus_width;
> +};
> +
> +static DEFINE_MUTEX(lpdd2_nvm_mutex);
> +
> +static inline map_word build_map_word(u_long myword)
> +{
> +       map_word val = { {0} };
> +       val.x[0] = myword;
> +       return val;
> +}
> +
> +static inline u_int build_mr_cfgmaks(u_int bus_width)
> +{
> +       u_int val = MR_CFGMASK;
> +
> +       if (bus_width == 0x0004)                /* x32 device */
> +               val = val<<16;
> +
> +       return val;
> +}
> +
> +static inline u_int build_sr_ok_datamask(u_int bus_width)
> +{
> +       u_int val = SR_OK_DATAMASK;
> +
> +       if (bus_width == 0x0004)                /* x32 device */
> +               val = (val<<16)+val;
> +
> +       return val;
> +}
> +
> +/*
> + * Enable lpddr2-nvm Overlay Window
> + */
> +static inline void ow_enable(struct map_info *map)
> +{
> +       struct pcm_int_data *pcm_data = map->fldrv_priv;
> +
> +       writel_relaxed(build_mr_cfgmaks(pcm_data->bus_width) | 0x18,
> +               pcm_data->reg_cfg);
> +       writel_relaxed(0x01, pcm_data->reg_data);
> +}
> +
> +/*
> + * Disable lpddr2-nvm Overlay Window
> + */
> +static inline void ow_disable(struct map_info *map)
> +{
> +       struct pcm_int_data *pcm_data = map->fldrv_priv;
> +
> +       writel_relaxed(build_mr_cfgmaks(pcm_data->bus_width) | 0x18,
> +               pcm_data->reg_cfg);
> +       writel_relaxed(0x02, pcm_data->reg_data);
> +}
> +
> +/*
> + * Execute lpddr2-nvm operations
> + */
> +static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code,
> +       u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf)
> +{
> +       map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} },
> +               mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} },
> +               exec_cmd = { {0} }, sr;
> +       map_word data_h = { {0} };      /* only for 2x x16 devices stacked
> */
> +       u_long i, status_reg, prg_buff_ofs;
> +       struct pcm_int_data *pcm_data = map->fldrv_priv;
> +       u_int sr_ok_datamask = build_sr_ok_datamask(pcm_data->bus_width);
> +
> +       /* Builds low and high words for OW Control Registers */
> +       add_l.x[0]      = cmd_add&0x0000FFFF;
> +       add_h.x[0]      = (cmd_add>>16)&0x0000FFFF;
> +       mpr_l.x[0]      = cmd_mpr&0x0000FFFF;
> +       mpr_h.x[0]      = (cmd_mpr>>16)&0x0000FFFF;
> +       cmd.x[0]        = cmd_code&0x0000FFFF;
> +       exec_cmd.x[0]   = 0x0001;
> +       data_l.x[0]     = cmd_data&0x0000FFFF;
> +       data_h.x[0]     = (cmd_data>>16)&0x0000FFFF; /* only for 2x x16 */
> +
> +       /* Set Overlay Window Control Registers */
> +       map_write(map, cmd,
> map->pfow_base+CMD_CODE_OFS*pcm_data->bus_width);
> +       map_write(map, data_l,
> map->pfow_base+CMD_DATA_OFS*pcm_data->bus_width);
> +       map_write(map, add_l,
> map->pfow_base+CMD_ADD_L_OFS*pcm_data->bus_width);
> +       map_write(map, add_h,
> map->pfow_base+CMD_ADD_H_OFS*pcm_data->bus_width);
> +       map_write(map, mpr_l,
> map->pfow_base+MPR_L_OFS*pcm_data->bus_width);
> +       map_write(map, mpr_h,
> map->pfow_base+MPR_H_OFS*pcm_data->bus_width);
> +       if (pcm_data->bus_width == 0x0004) {    /* 2x16 devices stacked */
> +               map_write(map, cmd, map->pfow_base +
> +                       CMD_CODE_OFS*pcm_data->bus_width + 2);
> +               map_write(map, data_h, map->pfow_base +
> +                       CMD_DATA_OFS*pcm_data->bus_width + 2);
> +               map_write(map, add_l, map->pfow_base +
> +                       CMD_ADD_L_OFS*pcm_data->bus_width + 2);
> +               map_write(map, add_h, map->pfow_base +
> +                       CMD_ADD_H_OFS*pcm_data->bus_width + 2);
> +               map_write(map, mpr_l, map->pfow_base +
> +                       MPR_L_OFS*pcm_data->bus_width + 2);
> +               map_write(map, mpr_h, map->pfow_base +
> +                       MPR_H_OFS*pcm_data->bus_width + 2);
> +       }
> +
> +       /* Fill Program Buffer */
> +       if ((cmd_code == LPDDR2_NVM_BUF_PROGRAM) ||
> +               (cmd_code == LPDDR2_NVM_BUF_OVERWRITE)) {
> +               prg_buff_ofs = (map_read(map, map->pfow_base +
> +                       PRG_BUFFER_OFS*pcm_data->bus_width)).x[0];
> +               for (i = 0; i < cmd_mpr; i++) {
> +                       map_write(map, build_map_word(buf[i]),
> map->pfow_base +
> +                       prg_buff_ofs + i);
> +               }
> +       }
> +
> +       /* Command Execute */
> +       map_write(map, exec_cmd, map->pfow_base+CMD_EXEC_OFS*
> +               pcm_data->bus_width);
> +       if (pcm_data->bus_width == 0x0004)      /* 2x16 devices stacked */
> +               map_write(map, exec_cmd, map->pfow_base +
> +                       CMD_EXEC_OFS*pcm_data->bus_width + 2);
> +
> +       /* Status Register Check */
> +       do {
> +               sr = map_read(map, map->pfow_base +
> +                       STATUS_REG_OFS*pcm_data->bus_width);
> +               status_reg = sr.x[0];
> +               if (pcm_data->bus_width == 0x0004) {/* 2x16 devices
> stacked */
> +                       sr = map_read(map, map->pfow_base +
> +                               STATUS_REG_OFS*pcm_data->bus_width + 2);
> +                       status_reg += sr.x[0]<<16;
> +               }
> +       } while ((status_reg&sr_ok_datamask) != sr_ok_datamask);
> +
> +       return (((status_reg&sr_ok_datamask) == sr_ok_datamask) ? 0 :
> -EIO);
> +}
> +
> +/*
> + * Execute lpddr2-nvm operations @ block level
> + */
> +static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add,
> +       uint64_t len, u_char block_op)
> +{
> +       struct map_info *map = mtd->priv;
> +       u_long add, end_add;
> +       int ret = 0;
> +
> +       mutex_lock(&lpdd2_nvm_mutex);
> +
> +       ow_enable(map);
> +
> +       add = start_add;
> +       end_add = add + len;
> +
> +       if ((add > mtd->size) || (end_add > mtd->size)) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       do {
> +               ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add,
> NULL);
> +               if (ret)
> +                       goto out;
> +               add += mtd->erasesize;
> +       } while (add < end_add);
> +
> +out:
> +       ow_disable(map);
> +       mutex_unlock(&lpdd2_nvm_mutex);
> +       return ret;
> +}
> +
> +/*
> + * verify presence of PFOW string
> + */
> +static int lpddr2_nvm_pfow_present(struct map_info *map)
> +{
> +       struct pcm_int_data *pcm_data = map->fldrv_priv;
> +       map_word pfow_val[4];
> +       unsigned int found = 1;
> +
> +       mutex_lock(&lpdd2_nvm_mutex);
> +
> +       ow_enable(map);
> +
> +       /* Load string from array */
> +       pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P *
> +                       pcm_data->bus_width);
> +       pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F *
> +                       pcm_data->bus_width);
> +       pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O *
> +                       pcm_data->bus_width);
> +       pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W *
> +                       pcm_data->bus_width);
> +
> +       /* Verify the string loaded vs expected */
> +       if (!map_word_equal(map, build_map_word('P'), pfow_val[0]))
> +               found = 0;
> +       if (!map_word_equal(map, build_map_word('F'), pfow_val[1]))
> +               found = 0;
> +       if (!map_word_equal(map, build_map_word('O'), pfow_val[2]))
> +               found = 0;
> +       if (!map_word_equal(map, build_map_word('W'), pfow_val[3]))
> +               found = 0;
> +
> +       ow_disable(map);
> +
> +       mutex_unlock(&lpdd2_nvm_mutex);
> +
> +       return found;
> +}
> +
> +/*
> + * lpddr2_nvm driver read method
> + */
> +static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add,
> +                               size_t len, size_t *retlen, u_char *buf)
> +{
> +       struct map_info *map = mtd->priv;
> +       int ret = 0;
> +
> +       mutex_lock(&lpdd2_nvm_mutex);
> +
> +       *retlen = len;
> +
> +       if ((start_add + len) > mtd->size) {
> +               pr_alert("lpddr2_nvm: read out of memory range\n");
> +               *retlen = 0;
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       map_copy_from(map, buf, start_add, *retlen);
> +
> +out:
> +       mutex_unlock(&lpdd2_nvm_mutex);
> +       return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver write method
> + */
> +static int lpddr2_nvm_write(struct mtd_info *mtd, loff_t start_add,
> +                               size_t len, size_t *retlen, const u_char
> *buf)
> +{
> +       struct map_info *map = mtd->priv;
> +       struct pcm_int_data *pcm_data = map->fldrv_priv;
> +       u_long add, current_len, tot_len, target_len, my_data;
> +       u_char *write_buf = (u_char *)buf;
> +       int ret = 0;
> +
> +       mutex_lock(&lpdd2_nvm_mutex);
> +
> +       ow_enable(map);
> +
> +       /* Set start value for the variables */
> +       add = start_add;
> +       target_len = len;
> +       tot_len = 0;
> +
> +       if ((start_add + len) > mtd->size) {
> +               pr_alert("lpddr2_nvm: write out of memory range\n");
> +               *retlen = 0;
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       while (tot_len < target_len) {
> +               if (!(IS_ALIGNED(add, mtd->writesize))) { /* do sw program
> */
> +                       my_data = write_buf[tot_len];
> +                       my_data += (write_buf[tot_len+1])<<8;
> +                       if (pcm_data->bus_width == 0x0004) {/* 2x16
> devices */
> +                               my_data += (write_buf[tot_len+2])<<16;
> +                               my_data += (write_buf[tot_len+3])<<24;
> +                       }
> +                       ret = lpddr2_nvm_do_op(map,
> LPDDR2_NVM_SW_OVERWRITE,
> +                               my_data, add, 0x00, NULL);
> +                       if (ret)
> +                               goto out;
> +
> +                       add += pcm_data->bus_width;
> +                       tot_len += pcm_data->bus_width;
> +               } else {                /* do buffer program */
> +                       current_len = min(target_len - tot_len,
> +                               (u_long) mtd->writesize);
> +                       ret = lpddr2_nvm_do_op(map,
> LPDDR2_NVM_BUF_OVERWRITE,
> +                               0x00, add, current_len, write_buf +
> tot_len);
> +                       if (ret)
> +                               goto out;
> +
> +                       add += current_len;
> +                       tot_len += current_len;
> +               }
> +       }
> +
> +out:
> +       *retlen = tot_len;
> +       ow_disable(map);
> +       mutex_unlock(&lpdd2_nvm_mutex);
> +       return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver erase method
> + */
> +static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info
> *instr)
> +{
> +       int ret = lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len,
> +               LPDDR2_NVM_ERASE);
> +       if (!ret) {
> +               instr->state = MTD_ERASE_DONE;
> +               mtd_erase_callback(instr);
> +       }
> +
> +       return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver unlock method
> + */
> +static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add,
> +       uint64_t len)
> +{
> +       return lpddr2_nvm_do_block_op(mtd, start_add, len,
> LPDDR2_NVM_UNLOCK);
> +}
> +
> +/*
> + * lpddr2_nvm driver lock method
> + */
> +static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,
> +       uint64_t len)
> +{
> +       return lpddr2_nvm_do_block_op(mtd, start_add, len,
> LPDDR2_NVM_LOCK);
> +}
> +
> +/*
> + * lpddr2_nvm driver probe method
> + */
> +static int lpddr2_nvm_probe(struct platform_device *pdev)
> +{
> +       int ret = 0;
> +       struct map_info *lpddr2_nvm_map;
> +       struct mtd_info *lpddr2_nvm_mtd;
> +       struct resource *address_range = platform_get_resource(pdev,
> +                                               IORESOURCE_MEM, 0);
> +       struct resource *control_regs = platform_get_resource(pdev,
> +                                               IORESOURCE_MEM, 1);
> +       struct resource *buswidth = platform_get_resource(pdev,
> +                                               IORESOURCE_BUS, 0);
> +       struct pcm_int_data *pcm_data;
> +
> +       /* Allocate memory control_regs data structures */
> +       pcm_data = kzalloc(sizeof(*pcm_data), GFP_KERNEL);
> +       if (!control_regs) {
> +               pr_alert(
> +               "lpddr2_nvm_probe: Failed to allocate memory for
> int_data\n");
> +               ret = 1;
> +               goto out;
> +       }
> +       pcm_data->reg_data =    (void *) control_regs->start;
> +       pcm_data->reg_cfg =     (void *) control_regs->end;
> +       pcm_data->bus_width =   (int) buswidth->start;
> +
> +       /* Allocate memory for map_info & mtd_info data structures */
> +       lpddr2_nvm_map = kzalloc(sizeof(*lpddr2_nvm_map), GFP_KERNEL);
> +       if (!lpddr2_nvm_map) {
> +               pr_alert(
> +               "lpddr2_nvm_probe: Failed to allocate memory for map\n");
> +               ret = 1;
> +               goto out;
> +       }
> +
> +       lpddr2_nvm_mtd = kzalloc(sizeof(*lpddr2_nvm_mtd), GFP_KERNEL);
> +       if (!lpddr2_nvm_mtd) {
> +               pr_alert(
> +               "lpddr2_nvm_probe: Failed to allocate memory for mtd\n");
> +               ret = 1;
> +               goto out;
> +       }
> +
> +       /* Reserve lpddr2_nvm address range */
> +       if (request_mem_region(address_range->start, (address_range->end -
> +               address_range->start + 1), "lpddr2_nvm") == NULL) {
> +               pr_alert(
> +               "lpddr2_nvm_probe: Unable to reserve memory address
> %#010x\n",
> +               address_range->start);
> +               ret = -EBUSY;
> +               goto out;
> +       }
> +
> +       /* Populate map_info data structure */
> +       *lpddr2_nvm_map = (struct map_info) {
> +               .virt           = ioremap_nocache(address_range->start,
> +
> (address_range->end-address_range->start+1)),
> +               .name           = pdev->dev.init_name,
> +               .phys           = address_range->start,
> +               .size           = address_range->end -
> address_range->start + 1,
> +               .bankwidth      = pcm_data->bus_width/2,
> +               .pfow_base      = OW_BASE_ADDRESS,
> +               .fldrv_priv     = pcm_data,
> +       };
> +
> +       simple_map_init(lpddr2_nvm_map);        /* fill with default
> methods */
> +
> +       /* Populate mtd_info data structure */
> +       *lpddr2_nvm_mtd = (struct mtd_info) {
> +               .name           = pdev->dev.init_name,
> +               .type           = MTD_RAM,
> +               .priv           = lpddr2_nvm_map,
> +               .size           = address_range->end -
> address_range->start + 1,
> +               .erasesize      = ERASE_BLOCKSIZE * pcm_data->bus_width,
> +               .writesize      = 1,
> +               .writebufsize   = WRITE_BUFFSIZE * pcm_data->bus_width,
> +               .flags          = (MTD_CAP_PCM | MTD_POWERUP_LOCK),
> +               ._read          = lpddr2_nvm_read,
> +               ._read_oob      = NULL,
> +               ._write         = lpddr2_nvm_write,
> +               ._write_oob     = NULL,
> +               ._erase         = lpddr2_nvm_erase,
> +               ._unlock        = lpddr2_nvm_unlock,
> +               ._lock          = lpddr2_nvm_lock,
> +               ._sync          = NULL,
> +               ._suspend       = NULL,
> +               ._resume        = NULL,
> +               ._block_isbad   = NULL,
> +               ._block_markbad = NULL,
> +       };
> +
> +       /* Verify the presence of the device looking for PFOW string */
> +       if (lpddr2_nvm_pfow_present(lpddr2_nvm_map)) {
> +               pr_alert("lpddr2_nvm_probe: device recognized\n");
> +               /* Register the mtd_partition structure */
> +               if (mtd_add_partition(lpddr2_nvm_mtd, "my_pcm",
> 0x10000000,
> +                       0x00)){
> +                       pr_alert(
> +                       "lpddr2_nvm_probe: Failed to add mtd
> partition\n");
> +                       ret = 1;
> +                       goto out;
> +               }
> +               ret = 0;
> +       } else {
> +               pr_alert("%s: PFOW string not found at address %#010lx\n",
> +                       lpddr2_nvm_map->name, lpddr2_nvm_map->pfow_base);
> +               ret = 1;
> +       }
> +
> +out:
> +       return ret;
> +}
> +
> +/* Initialize platform_driver data structure for lpddr2_nvm */
> +static struct platform_driver lpddr2_nvm_drv = {
> +       .driver         = {
> +               .name   = "lpddr2_nvm",
> +       },
> +       .probe          = lpddr2_nvm_probe,
> +       .remove         = NULL,
> +       .suspend        = NULL,
> +       .resume         = NULL,
> +};
> +
> +module_platform_driver(lpddr2_nvm_drv);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti at gmail.com>");
> +MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");
> +
> diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
> index 36eace0..33f3036 100644
> --- a/include/mtd/mtd-abi.h
> +++ b/include/mtd/mtd-abi.h
> @@ -109,6 +109,7 @@ struct mtd_write_req {
>  #define MTD_CAP_RAM            (MTD_WRITEABLE | MTD_BIT_WRITEABLE |
> MTD_NO_ERASE)
>  #define MTD_CAP_NORFLASH       (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
>  #define MTD_CAP_NANDFLASH      (MTD_WRITEABLE)
> +#define MTD_CAP_PCM            (MTD_WRITEABLE | MTD_BIT_WRITEABLE |
> MTD_NO_ERASE)
>
>  /* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
>  #define MTD_NANDECC_OFF                0       // Switch off ECC (Not
> recommended)
> --
> 1.7.9.5
>


From josh.wu at atmel.com  Wed Jun 19 02:23:11 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:11 +0800
Subject: [PATCH v4 0/6] mtd: atmel_nand: enable Nand Flash Controller (NFC)
 support
Message-ID: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>

This patch series enable NFC support for SAMA5 soc. It can send command,
address cycles automaticly. Also when enable NFC sram, NFC will transfer
data to sram. Which can save lots of cpu time.

The mtd speed test results (non-NFC vs NFC), run in sama5d3x-ek with DMA
enable, is in the end of this patch.

v3 --> v4:
 1) refine the commit message for ofpart.c patch and also change the
    description in partition.txt
 2) remove len parameter for ofpart.c's change.
 3) use devm_ioremap_resource instead of devm_requrest_and_ioremap.
 4) add BIT_POS macro definition for magic number.

v2 --> v3:
 1) Change the dts usage for NFC. Now use a NFC child node of atmel nand
    to enable NFC driver. In this way the atmel nand driver will include
    a NFC driver, which will be probed if dts has NFC node.
 2) can enable/disable NFC write by sram in dts.
 3) merged J.C's patch(use devm_xxx to simple the code) in this series.
 4) remove unused NFC register definitions. Change the definition names.
 5) trival fix accroding to J.C's suggestion.
 6) modify the ofpart.c for child node check. If the child node has compatible
    property then this node is a device not a partition.

v1 --> v2:
 1) rebase it with latest l2-mtd git tree: 
    - remove useless nand commands (NAND_CMD_DEPLETE1, NAND_CMD_STATUS_ERRORx).
    - adopt to the new nand write function's parameters. Add error message when
      handle subpage write via nfc sram.
 2) rewrite pmecc_enable function. Now I use exist NAND_ECC_READ/WRITE const
    instead of using a new enum definition.

Jean-Christophe PLAGNIOL-VILLARD (1):
  MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap

Josh Wu (5):
  mtd: atmel_nand: replace pmecc enable code with one function.
  mtd: atmel_nand: add Nand Flash Controller (NFC) support
  mtd: atmel_nand: enable Nand Flash Controller (NFC) read data via
    sram
  mtd: atmel_nand: enable Nand Flash Controller (NFC) write via sram
  mtd: ofpart: add compatible check for child nodes

 .../devicetree/bindings/mtd/atmel-nand.txt         |   28 +
 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/nand/atmel_nand.c                      |  876 ++++++++++++++++----
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++
 drivers/mtd/ofpart.c                               |   13 +-
 5 files changed, 853 insertions(+), 163 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h


mtd_speedtest is run in 60M partition with DMA enabled for two cases:
 1. Using NFC and sram read/write with DMA enabled.
 2. Using Non-NFC with DMA enabled.

Summary of the two test results:
 1. With NFC and sram read/write enabled, the write speed will become %10 slower
    and the cpu load also is reduce a lot (50% -> 20%):
                          Non-NFC                  NFC
      Page write Speed:   5536KiB : 46% ~ 64% --> 4989KiB : 13% ~ 22%
      2 Page write speed: 5567KiB : 52% ~ 69% --> 5043KiB : 10% ~ 20%

 2. With NFC and sram read/write enabled, the read speed is almost same and the
    cpu load is reduced (30% -> 15%):
                          Non-NFC                  NFC
      Page read Speed:    9361KiB : %24 ~ 46% --> 9340KiB : 13% ~ 19%
      2 Page read Speed:  9361KiB : %21 ~ 57% --> 9426KiB :  8% ~ 15%

Following is the detail test log:

case 1: Non-NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
top -n 130 -d 1 | grep speedtest
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     D     1164   0%  53% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  58% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  53% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  60% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock write speed is 5594 KiB/s
mtd_speedtest: testing eraseblock read speed
  513   504 root     R     1164   0%  27% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   5% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   1% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   2% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%   1% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock read speed is 9442 KiB/s
mtd_speedtest: testing page write speed
  513   504 root     R     1164   0%  46% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  64% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  64% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  59% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  62% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  60% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page write speed is 5536 KiB/s
mtd_speedtest: testing page read speed
  513   504 root     R     1164   0%  46% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  30% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  30% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  26% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  25% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page read speed is 9361 KiB/s
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: testing 2 page write speed
  513   504 root     R     1164   0%  69% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  56% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  61% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  61% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  52% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  55% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  58% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page write speed is 5567 KiB/s
mtd_speedtest: testing 2 page read speed
  513   504 root     D     1164   0%  57% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  26% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  21% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  23% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  24% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  25% insmod /root/mtd_test/mtd_speedtest.ko
  513   504 root     R     1164   0%  23% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9361 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 167411 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
  513   504 root     R     1164   0%  74% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 4x multi-block erase speed is 301176 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 326808 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 328556 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 325079 KiB/s
mtd_speedtest: finished
=================================================


case 2: NFC with DMA:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 62914560, eraseblock size 131072, page size 2048, count of eraseblocks 480, pages per eraseblock 64, OOB size 64
mtd_speedtest: scanning for bad eraseblocks
mtd_speedtest: scanned 480 eraseblocks, 0 are bad
top -n 130 -d 1 | grep speedtest
mtd_speedtest: testing eraseblock write speed
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  10% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     D     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     D     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   9% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock write speed is 5105 KiB/s
mtd_speedtest: testing eraseblock read speed
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   6% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: eraseblock read speed is 9512 KiB/s
  514   504 root     R     1164   0%   6% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: testing page write speed
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  11% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  22% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page write speed is 4989 KiB/s
mtd_speedtest: testing page read speed
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  18% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  19% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: page read speed is 9340 KiB/s
mtd_speedtest: testing 2 page write speed
  514   504 root     R     1164   0%  20% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  10% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  18% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  16% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  17% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  13% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page write speed is 5043 KiB/s
mtd_speedtest: testing 2 page read speed
  514   504 root     R     1164   0%   8% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%   9% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  14% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
  514   504 root     R     1164   0%  15% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 2 page read speed is 9426 KiB/s
mtd_speedtest: Testing erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: erase speed is 157943 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 308743 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 313469 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 315076 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
  514   504 root     R     1164   0%  12% insmod /root/mtd_test/mtd_speedtest.ko
mtd_speedtest: 32x multi-block erase speed is 298252 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 311878 KiB/s
mtd_speedtest: finished
=================================================

-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:12 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:12 +0800
Subject: [PATCH 1/6] MTD: atmel_nand: use devm_xxx gpio kzalloc,
 gpio and ioremap
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-2-git-send-email-josh.wu@atmel.com>

From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>

this will allow to simply the error and remove path

Cc: linux-mtd at lists.infradead.org
Cc: Nicolas Ferre <nicolas.ferre at atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
[josh.wu at atmel.com: fix checkpatch warnings and rebase to latest mtd git tree]
[josh.wu at atmel.com: replace devm_request_and_ioremap with devm_ioremap_resource]
Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v3 --> v4:
  use devm_ioremap_resource instead of devm_request_and_ioremap.

 drivers/mtd/nand/atmel_nand.c |  182 +++++++++++++++--------------------------
 1 file changed, 66 insertions(+), 116 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..d39f364 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -366,43 +366,34 @@ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 			table_size * sizeof(int16_t);
 }
 
-static void pmecc_data_free(struct atmel_nand_host *host)
-{
-	kfree(host->pmecc_partial_syn);
-	kfree(host->pmecc_si);
-	kfree(host->pmecc_lmu);
-	kfree(host->pmecc_smu);
-	kfree(host->pmecc_mu);
-	kfree(host->pmecc_dmu);
-	kfree(host->pmecc_delta);
-}
-
 static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
 	const int cap = host->pmecc_corr_cap;
+	int size;
+
+	size = (2 * cap + 1) * sizeof(int16_t);
+	host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_lmu = devm_kzalloc(host->dev,
+			(cap + 1) * sizeof(int16_t), GFP_KERNEL);
+	host->pmecc_smu = devm_kzalloc(host->dev,
+			(cap + 2) * size, GFP_KERNEL);
+
+	size = (cap + 1) * sizeof(int);
+	host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
+
+	if (!host->pmecc_partial_syn ||
+		!host->pmecc_si ||
+		!host->pmecc_lmu ||
+		!host->pmecc_smu ||
+		!host->pmecc_mu ||
+		!host->pmecc_dmu ||
+		!host->pmecc_delta)
+		return -ENOMEM;
 
-	host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-
-	if (host->pmecc_partial_syn &&
-			host->pmecc_si &&
-			host->pmecc_lmu &&
-			host->pmecc_smu &&
-			host->pmecc_mu &&
-			host->pmecc_dmu &&
-			host->pmecc_delta)
-		return 0;
-
-	/* error happened */
-	pmecc_data_free(host);
-	return -ENOMEM;
+	return 0;
 }
 
 static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
@@ -1023,27 +1014,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		goto err;
 	}
 
 	regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-	if (regs_pmerr && regs_rom) {
-		host->pmerrloc_base = ioremap(regs_pmerr->start,
-			resource_size(regs_pmerr));
-		host->pmecc_rom_base = ioremap(regs_rom->start,
-			resource_size(regs_rom));
+	host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 
-	if (!host->pmerrloc_base || !host->pmecc_rom_base) {
-		dev_err(host->dev,
-			"Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
-		err_no = -EIO;
-		goto err_pmloc_ioremap;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1068,7 +1060,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
 			dev_err(host->dev, "No room for ECC bytes\n");
 			err_no = -EINVAL;
-			goto err_no_ecc_room;
+			goto err;
 		}
 		pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
 					mtd->oobsize,
@@ -1093,7 +1085,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 	if (err_no) {
 		dev_err(host->dev,
 				"Cannot allocate memory for PMECC computation!\n");
-		goto err_pmecc_data_alloc;
+		goto err;
 	}
 
 	nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
@@ -1103,15 +1095,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 
 	return 0;
 
-err_pmecc_data_alloc:
-err_no_ecc_room:
-err_pmloc_ioremap:
-	iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-err_pmecc_ioremap:
+err:
 	return err_no;
 }
 
@@ -1414,10 +1398,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 	}
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 
 	/* ECC is calculated for the whole page (1 step) */
@@ -1472,27 +1456,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	int res;
 	struct pinctrl *pinctrl;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
-
 	/* Allocate memory for the device structure (and zero it) */
-	host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 	if (!host) {
 		printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
 		return -ENOMEM;
 	}
 
-	host->io_phys = (dma_addr_t)mem->start;
-
-	host->io_base = ioremap(mem->start, resource_size(mem));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
@@ -1500,7 +1478,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	if (pdev->dev.of_node) {
 		res = atmel_of_init_port(host, pdev->dev.of_node);
 		if (res)
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 	} else {
 		memcpy(&host->board, pdev->dev.platform_data,
 		       sizeof(struct atmel_nand_data));
@@ -1519,16 +1497,17 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	if (IS_ERR(pinctrl)) {
 		dev_err(host->dev, "Failed to request pinctrl\n");
 		res = PTR_ERR(pinctrl);
-		goto err_ecc_ioremap;
+		goto err_nand_ioremap;
 	}
 
 	if (gpio_is_valid(host->board.rdy_pin)) {
-		res = gpio_request(host->board.rdy_pin, "nand_rdy");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.rdy_pin, "nand_rdy");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request rdy gpio %d\n",
 				host->board.rdy_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		res = gpio_direction_input(host->board.rdy_pin);
@@ -1536,19 +1515,20 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"can't request input direction rdy gpio %d\n",
 				host->board.rdy_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		nand_chip->dev_ready = atmel_nand_device_ready;
 	}
 
 	if (gpio_is_valid(host->board.enable_pin)) {
-		res = gpio_request(host->board.enable_pin, "nand_enable");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.enable_pin, "nand_enable");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request enable gpio %d\n",
 				host->board.enable_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 
 		res = gpio_direction_output(host->board.enable_pin, 1);
@@ -1556,7 +1536,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"can't request output direction enable gpio %d\n",
 				host->board.enable_pin);
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 		}
 	}
 
@@ -1573,7 +1553,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	atmel_nand_enable(host);
 
 	if (gpio_is_valid(host->board.det_pin)) {
-		res = gpio_request(host->board.det_pin, "nand_det");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.det_pin, "nand_det");
 		if (res < 0) {
 			dev_err(&pdev->dev,
 				"can't request det gpio %d\n",
@@ -1651,16 +1632,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return res;
 
 err_scan_tail:
-	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-		pmecc_data_free(host);
-	}
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
 err_hw_ecc:
 err_scan_ident:
 err_no_card:
@@ -1668,10 +1641,7 @@ err_no_card:
 	platform_set_drvdata(pdev, NULL);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
-	kfree(host);
 	return res;
 }
 
@@ -1691,31 +1661,11 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
 		pmerrloc_writel(host->pmerrloc_base, ELDIS,
 				PMERRLOC_DISABLE);
-		pmecc_data_free(host);
 	}
 
-	if (gpio_is_valid(host->board.det_pin))
-		gpio_free(host->board.det_pin);
-
-	if (gpio_is_valid(host->board.enable_pin))
-		gpio_free(host->board.enable_pin);
-
-	if (gpio_is_valid(host->board.rdy_pin))
-		gpio_free(host->board.rdy_pin);
-
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
-	iounmap(host->io_base);
-	kfree(host);
-
 	return 0;
 }
 
-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:13 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:13 +0800
Subject: [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one
 function.
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-3-git-send-email-josh.wu@atmel.com>

Signed-off-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
 drivers/mtd/nand/atmel_nand.c |   40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index d39f364..cb8362e 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -754,6 +754,29 @@ normal_check:
 	return total_err;
 }
 
+static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
+{
+	u32 val;
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+	val = pmecc_readl_relaxed(host->ecc, CFG);
+
+	if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
+		dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
+		return;
+	}
+
+	if (ecc_op == NAND_ECC_READ)
+		pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
+			| PMECC_CFG_AUTO_ENABLE);
+	else
+		pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
+			& ~PMECC_CFG_AUTO_ENABLE);
+
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+}
+
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 {
@@ -765,13 +788,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	unsigned long end_time;
 	int bitflips = 0;
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
-		& ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+	pmecc_enable(host, NAND_ECC_READ);
 
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
@@ -804,14 +821,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 	int i, j;
 	unsigned long end_time;
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
-		PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+	pmecc_enable(host, NAND_ECC_WRITE);
 
 	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
 
-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:14 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:14 +0800
Subject: =?UTF-8?q?=5BPATCH=203/6=5D=20mtd=3A=20atmel=5Fnand=3A=20add=20Nand=20Flash=20Controller=20=28NFC=29=20support?=
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-4-git-send-email-josh.wu@atmel.com>

Nand Flash Controller (NFC) can handle automatic transfers, sending the
commands and address cycles to the NAND Flash.

To use NFC in this driver, user needs to add NFC child node in nand flash
driver. The NFC child node includes NFC's compatible string and regiters
of the address and size of NFC command registers, NFC registers (embedded
in HSMC) and NFC SRAM.
Also user need to set up the HSMC irq, which use to check whether nfc
command is finish or not.

This driver has been tested on SAMA5D3X-EK board with JFFS2, YAFFS,
UBIFS and mtd-utils.

I put the part of the mtd_speedtest result here for your information.
>From the mtd_speedtest, we can see the NFC will reduce the %50 of cpu load
when writing nand flash. No change when reading.
In the meantime, the speed will be slow about %8.

- commands use to test:
    #insmod /mnt/mtd_speedtest.ko dev=2 &
    #top -n 30 -d 1 | grep speedtest

- test result:

Before the patch:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
  515   495 root     R     1164   0%  93% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  99% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5768 KiB/s
mtd_speedtest: testing eraseblock read speed
  515   495 root     R     1164   0%  92% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 5932 KiB/s
mtd_speedtest: testing page write speed
  515   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  98% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5770 KiB/s
mtd_speedtest: testing page read speed
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  89% insmod /mnt/mtd_speedtest.ko dev=2
  515   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5910 KiB/s

After the patch:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock write speed
  509   495 root     D     1164   0%  49% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  50% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  47% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5370 KiB/s
mtd_speedtest: testing eraseblock read speed
  509   495 root     R     1164   0%  92% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  91% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  95% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 5715 KiB/s
mtd_speedtest: testing page write speed
  509   495 root     D     1164   0%  48% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  47% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  50% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5224 KiB/s
mtd_speedtest: testing page read speed
  509   495 root     R     1164   0%  89% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  94% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%  93% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 5641 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v3 --> v4:
  - remove printk and use dev_err.
  - use macro definition for the BIT_POS for bit shift instead of magical
    numbers.
  - add/remove blank line for coding style.

v2 --> v3:
  - Add a NFC child node of atmel nand to enable NFC.
  - So add a NFC driver which use to initialize the NFC reg resources.
  - remove unused NFC register definitions.
  - modify NFC register definition names.

 .../devicetree/bindings/mtd/atmel-nand.txt         |   26 ++
 drivers/mtd/nand/atmel_nand.c                      |  411 ++++++++++++++++++--
 drivers/mtd/nand/atmel_nand_nfc.h                  |   98 +++++
 3 files changed, 502 insertions(+), 33 deletions(-)
 create mode 100644 drivers/mtd/nand/atmel_nand_nfc.h

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index d555421..6a267cb 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -29,6 +29,12 @@ Optional properties:
   sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
+  - Required properties:
+    - compatible : "atmel,sama5d3-nfc".
+    - reg : should specify the address and size used for NFC command registers,
+            NFC registers and NFC Sram. NFC Sram address and size can be absent
+            if don't want to use it.
 
 Examples:
 nand0: nand at 40000000,0 {
@@ -77,3 +83,23 @@ nand0: nand at 40000000 {
 		...
 	};
 };
+
+/* for NFC supported chips */
+nand0: nand at 40000000 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+        ...
+        nfc at 70000000 {
+		compatible = "atmel,sama5d3-nfc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <
+			0x70000000 0x10000000	/* NFC Command Registers */
+			0xffffc000 0x00000070	/* NFC HSMC regs */
+			0x00200000 0x00100000	/* NFC SRAM banks */
+		>;
+	};
+};
+
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index cb8362e..7c663cc 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     ? Copyright 2012 ATMEL, Hong Xu
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     ? Copyright 2013 ATMEL, Josh Wu (josh.wu at atmel.com)
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -37,9 +40,11 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/platform_data/atmel.h>
 #include <linux/pinctrl/consumer.h>
 
@@ -58,6 +63,7 @@ module_param(on_flash_bbt, int, 0);
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
+#include "atmel_nand_nfc.h"	/* Nand Flash Controller definition */
 
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -85,6 +91,17 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 	},
 };
 
+struct atmel_nfc {
+	void __iomem		*base_cmd_regs;
+	void __iomem		*hsmc_regs;
+	void __iomem		*sram_bank0;
+	dma_addr_t		sram_bank0_phys;
+
+	bool			is_initialized;
+	struct completion	comp_nfc;
+};
+static struct atmel_nfc	nand_nfc;
+
 struct atmel_nand_host {
 	struct nand_chip	nand_chip;
 	struct mtd_info		mtd;
@@ -97,6 +114,8 @@ struct atmel_nand_host {
 	struct completion	comp;
 	struct dma_chan		*dma_chan;
 
+	struct atmel_nfc	*nfc;
+
 	bool			has_pmecc;
 	u8			pmecc_corr_cap;
 	u16			pmecc_sector_size;
@@ -186,6 +205,56 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
 }
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	if (gpio_is_valid(host->board.rdy_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.rdy_pin, "nand_rdy");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		res = gpio_direction_input(host->board.rdy_pin);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request input direction rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		chip->dev_ready = atmel_nand_device_ready;
+	}
+
+	if (gpio_is_valid(host->board.enable_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.enable_pin, "nand_enable");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+
+		res = gpio_direction_output(host->board.enable_pin, 1);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request output direction enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+	}
+
+	return res;
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -1342,6 +1411,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
 	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 
+	/* load the nfc driver if there is */
+	of_platform_populate(np, NULL, NULL, host->dev);
+
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 		return 0;	/* Not using PMECC */
 
@@ -1453,6 +1525,239 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 	return 0;
 }
 
+/* SMC interrupt service routine */
+static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
+{
+	struct atmel_nand_host *host = dev_id;
+	u32 status, mask, pending;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	status = nfc_readl(host->nfc->hsmc_regs, SR);
+	mask = nfc_readl(host->nfc->hsmc_regs, IMR);
+	pending = status & mask;
+
+	if (pending & NFC_SR_XFR_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
+	} else if (pending & NFC_SR_RB_EDGE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
+	} else if (pending & NFC_SR_CMD_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
+	} else {
+		ret = IRQ_NONE;
+	}
+
+	return ret;
+}
+
+/* NFC(Nand Flash Controller) related functions */
+static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
+{
+	unsigned long timeout;
+	init_completion(&host->nfc->comp_nfc);
+
+	/* Enable interrupt that need to wait for */
+	nfc_writel(host->nfc->hsmc_regs, IER, flag);
+
+	timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
+			msecs_to_jiffies(NFC_TIME_OUT_MS));
+	if (timeout)
+		return 0;
+
+	/* Time out to wait for the interrupt */
+	dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
+	return -ETIMEDOUT;
+}
+
+static int nfc_send_command(struct atmel_nand_host *host,
+	unsigned int cmd, unsigned int addr, unsigned char cycle0)
+{
+	unsigned long timeout;
+	dev_dbg(host->dev,
+		"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
+		cmd, addr, cycle0);
+
+	timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+	while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
+			& NFCADDR_CMD_NFCBUSY) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(host->dev,
+				"Time out to wait CMD_NFCBUSY ready!\n");
+			return -ETIMEDOUT;
+		}
+	}
+	nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
+	nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
+	return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
+}
+
+static int nfc_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+	if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
+		return 1;
+	return 0;
+}
+
+static void nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+
+	if (chip == -1)
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
+	else
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
+}
+
+static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
+		unsigned int *addr1234, unsigned int *cycle0)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	int acycle = 0;
+	unsigned char addr_bytes[8];
+	int index = 0, bit_shift;
+
+	BUG_ON(addr1234 == NULL || cycle0 == NULL);
+
+	*cycle0 = 0;
+	*addr1234 = 0;
+
+	if (column != -1) {
+		if (chip->options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		addr_bytes[acycle++] = column & 0xff;
+		if (mtd->writesize > 512)
+			addr_bytes[acycle++] = (column >> 8) & 0xff;
+	}
+
+	if (page_addr != -1) {
+		addr_bytes[acycle++] = page_addr & 0xff;
+		addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
+		if (chip->chipsize > (128 << 20))
+			addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
+	}
+
+	if (acycle > 4)
+		*cycle0 = addr_bytes[index++];
+
+	for (bit_shift = 0; index < acycle; bit_shift += 8)
+		*addr1234 += addr_bytes[index++] << bit_shift;
+
+	/* return acycle in cmd register */
+	return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
+}
+
+static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
+				int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	unsigned long timeout;
+	unsigned int nfc_addr_cmd = 0;
+
+	unsigned int cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+
+	/* Set default settings: no cmd2, no addr cycle. read from nand */
+	unsigned int cmd2 = 0;
+	unsigned int vcmd2 = 0;
+	int acycle = NFCADDR_CMD_ACYCLE_NONE;
+	int csid = NFCADDR_CMD_CSID_3;
+	int dataen = NFCADDR_CMD_DATADIS;
+	int nfcwr = NFCADDR_CMD_NFCRD;
+	unsigned int addr1234 = 0;
+	unsigned int cycle0 = 0;
+	bool do_addr = true;
+
+	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
+	     __func__, command, column, page_addr);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
+		nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+		udelay(chip->chip_delay);
+
+		nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
+		timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
+			if (time_after(jiffies, timeout)) {
+				dev_err(host->dev,
+					"Time out to wait status ready!\n");
+				break;
+			}
+		}
+		return;
+	case NAND_CMD_STATUS:
+		do_addr = false;
+		break;
+	case NAND_CMD_PARAM:
+	case NAND_CMD_READID:
+		do_addr = false;
+		acycle = NFCADDR_CMD_ACYCLE_1;
+		if (column != -1)
+			addr1234 = column;
+		break;
+	case NAND_CMD_RNDOUT:
+		cmd2 = NAND_CMD_RNDOUTSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		if (command == NAND_CMD_READOOB) {
+			column += mtd->writesize;
+			command = NAND_CMD_READ0; /* only READ0 is valid */
+			cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+		}
+
+		cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	/* For prgramming command, the cmd need set to write enable */
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
+		nfcwr = NFCADDR_CMD_NFCWR;
+		break;
+	default:
+		break;
+	}
+
+	if (do_addr)
+		acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
+				&cycle0);
+
+	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
+	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+
+	/*
+	 * Program and erase have their own busy handlers status, sequential
+	 * in, and deplete1 need no delay.
+	 */
+	switch (command) {
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_RNDIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_RNDOUT:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_READID:
+		return;
+
+	case NAND_CMD_READ0:
+		/* fall through */
+	default:
+		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
+	}
+}
+
+static struct platform_driver atmel_nand_nfc_driver;
 /*
  * Probe for the NAND device.
  */
@@ -1463,7 +1768,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	struct nand_chip *nand_chip;
 	struct resource *mem;
 	struct mtd_part_parser_data ppdata = {};
-	int res;
+	int res, irq;
 	struct pinctrl *pinctrl;
 
 	/* Allocate memory for the device structure (and zero it) */
@@ -1473,6 +1778,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	res = platform_driver_register(&atmel_nand_nfc_driver);
+	if (res)
+		dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
+
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(host->io_base)) {
@@ -1501,7 +1810,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	/* Set address of NAND IO lines */
 	nand_chip->IO_ADDR_R = host->io_base;
 	nand_chip->IO_ADDR_W = host->io_base;
-	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
 	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
 	if (IS_ERR(pinctrl)) {
@@ -1510,44 +1818,34 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		goto err_nand_ioremap;
 	}
 
-	if (gpio_is_valid(host->board.rdy_pin)) {
-		res = devm_gpio_request(&pdev->dev,
-				host->board.rdy_pin, "nand_rdy");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
-
-		res = gpio_direction_input(host->board.rdy_pin);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request input direction rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_nand_ioremap;
-		}
+	if (nand_nfc.is_initialized) {
+		/* NFC driver is probed and initialized */
+		host->nfc = &nand_nfc;
 
-		nand_chip->dev_ready = atmel_nand_device_ready;
-	}
+		nand_chip->select_chip = nfc_select_chip;
+		nand_chip->dev_ready = nfc_device_ready;
+		nand_chip->cmdfunc = nfc_nand_command;
 
-	if (gpio_is_valid(host->board.enable_pin)) {
-		res = devm_gpio_request(&pdev->dev,
-				host->board.enable_pin, "nand_enable");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request enable gpio %d\n",
-				host->board.enable_pin);
+		/* Initialize the interrupt for NFC */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(host->dev, "Cannot get HSMC irq!\n");
 			goto err_nand_ioremap;
 		}
 
-		res = gpio_direction_output(host->board.enable_pin, 1);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request output direction enable gpio %d\n",
-				host->board.enable_pin);
+		res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+				0, "hsmc", host);
+		if (res) {
+			dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+				irq);
 			goto err_nand_ioremap;
 		}
+	} else {
+		res = atmel_nand_set_enable_ready_pins(mtd);
+		if (res)
+			goto err_nand_ioremap;
+
+		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 
 	nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1652,6 +1950,7 @@ err_no_card:
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 err_nand_ioremap:
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 	return res;
 }
 
@@ -1676,6 +1975,8 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 
+	platform_driver_unregister(&atmel_nand_nfc_driver);
+
 	return 0;
 }
 
@@ -1688,6 +1989,50 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+	struct atmel_nfc *nfc = &nand_nfc;
+	struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+	nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+	if (IS_ERR(nfc->base_cmd_regs))
+		return PTR_ERR(nfc->base_cmd_regs);
+
+	nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+	if (IS_ERR(nfc->hsmc_regs))
+		return PTR_ERR(nfc->hsmc_regs);
+
+	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (nfc_sram) {
+		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
+		if (IS_ERR(nfc->sram_bank0))
+			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+					PTR_ERR(nfc->sram_bank0));
+		else
+			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+	}
+
+	nfc->is_initialized = true;
+	dev_info(&pdev->dev, "NFC is probed.\n");
+	return 0;
+}
+
+static struct of_device_id atmel_nand_nfc_match[] = {
+	{ .compatible = "atmel,sama5d3-nfc" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver atmel_nand_nfc_driver = {
+	.driver = {
+		.name = "atmel_nand_nfc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_nand_nfc_match),
+	},
+	.probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
new file mode 100644
index 0000000..4efd117
--- /dev/null
+++ b/drivers/mtd/nand/atmel_nand_nfc.h
@@ -0,0 +1,98 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * ? Copyright 2013 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG	0x00		/* NFC Configuration Register */
+#define		NFC_CFG_PAGESIZE	(7 << 0)
+#define			NFC_CFG_PAGESIZE_512	(0 << 0)
+#define			NFC_CFG_PAGESIZE_1024	(1 << 0)
+#define			NFC_CFG_PAGESIZE_2048	(2 << 0)
+#define			NFC_CFG_PAGESIZE_4096	(3 << 0)
+#define			NFC_CFG_PAGESIZE_8192	(4 << 0)
+#define		NFC_CFG_WSPARE		(1 << 8)
+#define		NFC_CFG_RSPARE		(1 << 9)
+#define		NFC_CFG_NFC_DTOCYC	(0xf << 16)
+#define		NFC_CFG_NFC_DTOMUL	(0x7 << 20)
+#define		NFC_CFG_NFC_SPARESIZE	(0x7f << 24)
+#define		NFC_CFG_NFC_SPARESIZE_BIT_POS	24
+
+#define ATMEL_HSMC_NFC_CTRL	0x04		/* NFC Control Register */
+#define		NFC_CTRL_ENABLE		(1 << 0)
+#define		NFC_CTRL_DISABLE	(1 << 1)
+
+#define ATMEL_HSMC_NFC_SR	0x08		/* NFC Status Register */
+#define		NFC_SR_XFR_DONE		(1 << 16)
+#define		NFC_SR_CMD_DONE		(1 << 17)
+#define		NFC_SR_RB_EDGE		(1 << 24)
+
+#define ATMEL_HSMC_NFC_IER	0x0c
+#define ATMEL_HSMC_NFC_IDR	0x10
+#define ATMEL_HSMC_NFC_IMR	0x14
+#define ATMEL_HSMC_NFC_CYCLE0	0x18		/* NFC Address Cycle Zero */
+#define		ATMEL_HSMC_NFC_ADDR_CYCLE0	(0xff)
+
+#define ATMEL_HSMC_NFC_BANK	0x1c		/* NFC Bank Register */
+#define		ATMEL_HSMC_NFC_BANK0		(0 << 0)
+#define		ATMEL_HSMC_NFC_BANK1		(1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+	writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+	readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1	(0xff << 2)	/* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD1_BIT_POS	2
+#define NFCADDR_CMD_CMD2	(0xff << 10)	/* Command for Cycle 2 */
+#define NFCADDR_CMD_CMD2_BIT_POS	10
+#define NFCADDR_CMD_VCMD2	(0x1 << 18)	/* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE	(0x7 << 19)	/* Number of Address required */
+#define		NFCADDR_CMD_ACYCLE_NONE		(0x0 << 19)
+#define		NFCADDR_CMD_ACYCLE_1		(0x1 << 19)
+#define		NFCADDR_CMD_ACYCLE_2		(0x2 << 19)
+#define		NFCADDR_CMD_ACYCLE_3		(0x3 << 19)
+#define		NFCADDR_CMD_ACYCLE_4		(0x4 << 19)
+#define		NFCADDR_CMD_ACYCLE_5		(0x5 << 19)
+#define NFCADDR_CMD_ACYCLE_BIT_POS	19
+#define NFCADDR_CMD_CSID	(0x7 << 22)	/* Chip Select Identifier */
+#define		NFCADDR_CMD_CSID_0		(0x0 << 22)
+#define		NFCADDR_CMD_CSID_1		(0x1 << 22)
+#define		NFCADDR_CMD_CSID_2		(0x2 << 22)
+#define		NFCADDR_CMD_CSID_3		(0x3 << 22)
+#define		NFCADDR_CMD_CSID_4		(0x4 << 22)
+#define		NFCADDR_CMD_CSID_5		(0x5 << 22)
+#define		NFCADDR_CMD_CSID_6		(0x6 << 22)
+#define		NFCADDR_CMD_CSID_7		(0x7 << 22)
+#define NFCADDR_CMD_DATAEN	(0x1 << 25)	/* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS	(0x0 << 25)	/* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD	(0x0 << 26)	/* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR	(0x1 << 26)	/* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY	(0x1 << 27)	/* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+	writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+	readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS		100
+#define	NFC_SRAM_BANK1_OFFSET	0x1200
+
+#endif
-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:15 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:15 +0800
Subject: [PATCH 4/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) read
 data via sram
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-5-git-send-email-josh.wu@atmel.com>

NFC has embedded sram which can use to transfer data. This patch enable reading
nand flash via NFC SRAM. It will minimize the CPU overhead.

This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
mtd-utils.

Here puts the part of mtd_speedtest (read test) result as following:
Compare with non-NFC mtd_speedtest result, reading will reduce %45 cpu load
with increase %80 speed.

- commands use to test:
  # insmod /mnt/mtd_speedtest.ko dev=2 &
  # top -n 30 -d 1 | grep speedtest

- test result:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock read speed
  509   495 root     D     1164   0%  28% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  26% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock read speed is 9403 KiB/s
mtd_speedtest: testing page read speed
  509   495 root     R     1164   0%  31% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  57% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  53% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  71% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page read speed is 9258 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
v3 --> v4:
  - use BIT_POS definition not magical number.

v2 --> v3:
  - if NFC sram address and size is specified then enable NFC sram read.
    Otherwise disable NFC sram read.

 drivers/mtd/nand/atmel_nand.c |  163 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 157 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 7c663cc..2e272a7 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -96,9 +96,13 @@ struct atmel_nfc {
 	void __iomem		*hsmc_regs;
 	void __iomem		*sram_bank0;
 	dma_addr_t		sram_bank0_phys;
+	bool			use_nfc_sram;
 
 	bool			is_initialized;
 	struct completion	comp_nfc;
+
+	/* Point to the sram bank which include readed data via NFC */
+	void __iomem		*data_in_sram;
 };
 static struct atmel_nfc	nand_nfc;
 
@@ -255,21 +259,43 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
 	return res;
 }
 
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+	int i;
+	u32 *t = trg;
+	const __iomem u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		*t++ = readl_relaxed(s++);
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 {
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
-	__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	}
 }
 
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 {
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
-	__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	}
 }
 
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
@@ -291,6 +317,40 @@ static void dma_complete_func(void *completion)
 	complete(completion);
 }
 
+static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
+{
+	/* NFC only has two banks. Must be 0 or 1 */
+	if (bank > 1)
+		return -EINVAL;
+
+	if (bank) {
+		/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
+		if (host->mtd.writesize > 2048)
+			return -EINVAL;
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
+	} else {
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
+	}
+
+	return 0;
+}
+
+static uint nfc_get_sram_off(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return NFC_SRAM_BANK1_OFFSET;
+	else
+		return 0;
+}
+
+static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
+	else
+		return host->nfc->sram_bank0_phys;
+}
+
 static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 			       int is_read)
 {
@@ -304,6 +364,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	void *p = buf;
 	int err = -EIO;
 	enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	struct atmel_nfc *nfc = host->nfc;
 
 	if (buf >= high_memory)
 		goto err_buf;
@@ -320,7 +381,12 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	}
 
 	if (is_read) {
-		dma_src_addr = host->io_phys;
+		if (nfc && nfc->data_in_sram)
+			dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
+				- (nfc->sram_bank0 + nfc_get_sram_off(host)));
+		else
+			dma_src_addr = host->io_phys;
+
 		dma_dst_addr = phys_addr;
 	} else {
 		dma_src_addr = phys_addr;
@@ -347,6 +413,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	dma_async_issue_pending(host->dma_chan);
 	wait_for_completion(&host->comp);
 
+	if (is_read && nfc && nfc->data_in_sram)
+		/* After read data from SRAM, need to increase the position */
+		nfc->data_in_sram += len;
+
 	err = 0;
 
 err_dma:
@@ -857,7 +927,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	unsigned long end_time;
 	int bitflips = 0;
 
-	pmecc_enable(host, NAND_ECC_READ);
+	if (!host->nfc || !host->nfc->use_nfc_sram)
+		pmecc_enable(host, NAND_ECC_READ);
 
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
@@ -1672,6 +1743,7 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	unsigned int addr1234 = 0;
 	unsigned int cycle0 = 0;
 	bool do_addr = true;
+	host->nfc->data_in_sram = NULL;
 
 	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
 	     __func__, command, column, page_addr);
@@ -1713,6 +1785,16 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 			command = NAND_CMD_READ0; /* only READ0 is valid */
 			cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
 		}
+		if (host->nfc->use_nfc_sram) {
+			/* Enable Data transfer to sram */
+			dataen = NFCADDR_CMD_DATAEN;
+
+			/* Need enable PMECC now, since NFC will transfer
+			 * data in bus after sending nfc read command.
+			 */
+			if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+				pmecc_enable(host, NAND_ECC_READ);
+		}
 
 		cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
 		vcmd2 = NFCADDR_CMD_VCMD2;
@@ -1734,6 +1816,10 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
 	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
 
+	if (dataen == NFCADDR_CMD_DATAEN)
+		if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
+			dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
+
 	/*
 	 * Program and erase have their own busy handlers status, sequential
 	 * in, and deplete1 need no delay.
@@ -1751,12 +1837,66 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 		return;
 
 	case NAND_CMD_READ0:
+		if (dataen == NFCADDR_CMD_DATAEN) {
+			host->nfc->data_in_sram = host->nfc->sram_bank0 +
+				nfc_get_sram_off(host);
+			return;
+		}
 		/* fall through */
 	default:
 		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
 	}
 }
 
+static int nfc_sram_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	/* Initialize the NFC CFG register */
+	unsigned int cfg_nfc = 0;
+
+	/* set page size and oob layout */
+	switch (mtd->writesize) {
+	case 512:
+		cfg_nfc = NFC_CFG_PAGESIZE_512;
+		break;
+	case 1024:
+		cfg_nfc = NFC_CFG_PAGESIZE_1024;
+		break;
+	case 2048:
+		cfg_nfc = NFC_CFG_PAGESIZE_2048;
+		break;
+	case 4096:
+		cfg_nfc = NFC_CFG_PAGESIZE_4096;
+		break;
+	case 8192:
+		cfg_nfc = NFC_CFG_PAGESIZE_8192;
+		break;
+	default:
+		dev_err(host->dev, "Unsupported page size for NFC.\n");
+		res = -ENXIO;
+		return res;
+	}
+
+	/* oob bytes size = (NFCSPARESIZE + 1) * 4
+	 * Max support spare size is 512 bytes. */
+	cfg_nfc |= (((mtd->oobsize / 4) - 1) << NFC_CFG_NFC_SPARESIZE_BIT_POS
+		& NFC_CFG_NFC_SPARESIZE);
+	/* default set a max timeout */
+	cfg_nfc |= NFC_CFG_RSPARE |
+			NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
+
+	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
+
+	nfc_set_sram_bank(host, 0);
+
+	dev_info(host->dev, "Using NFC Sram read\n");
+
+	return 0;
+}
+
 static struct platform_driver atmel_nand_nfc_driver;
 /*
  * Probe for the NAND device.
@@ -1926,6 +2066,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			goto err_hw_ecc;
 	}
 
+	/* initialize the nfc configuration register */
+	if (host->nfc && host->nfc->use_nfc_sram) {
+		res = nfc_sram_init(mtd);
+		if (res) {
+			host->nfc->use_nfc_sram = false;
+			dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
+		}
+	}
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		res = -ENXIO;
@@ -2007,11 +2156,13 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
 	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	if (nfc_sram) {
 		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
-		if (IS_ERR(nfc->sram_bank0))
+		if (IS_ERR(nfc->sram_bank0)) {
 			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
 					PTR_ERR(nfc->sram_bank0));
-		else
+		} else {
+			nfc->use_nfc_sram = true;
 			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+		}
 	}
 
 	nfc->is_initialized = true;
-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:16 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:16 +0800
Subject: [PATCH 5/6] mtd: atmel_nand: enable Nand Flash Controller (NFC) write
 via sram
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-6-git-send-email-josh.wu@atmel.com>

This patch enable writing nand flash via NFC SRAM. It will minimize the CPU
overhead. The SRAM write only support ECC_NONE and ECC_HW with PMECC.

To enable this NFC write by SRAM feature, you can add a string in dts under
NFC driver node.

This driver has been tested on SAMA5D3X-EK with JFFS2, YAFFS2, UBIFS and
mtd-utils.

Here is part of mtd_speedtest (writing test) result, compare with non-NFC
writing, it reduces %65 cpu load with loss %12 speed.

- commands use to test:
  # insmod /mnt/mtd_speedtest.ko dev=2 &
  # top -n 30 -d 1 | grep speedtest

- test result:
=================================================
mtd_speedtest: MTD device: 2
mtd_speedtest: MTD device size 41943040, eraseblock size 131072, page size 2048, count of eraseblocks 320, pages per eraseblock 64, OOB size 64
mtd_speedtest: testing eraseblock write speed
  509   495 root     D     1164   0%   7% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%   8% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     R     1164   0%   5% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: eraseblock write speed is 5194 KiB/s
mtd_speedtest: testing page write speed
  509   495 root     D     1164   0%  32% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  27% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  25% insmod /mnt/mtd_speedtest.ko dev=2
  509   495 root     D     1164   0%  30% insmod /mnt/mtd_speedtest.ko dev=2
mtd_speedtest: page write speed is 5024 KiB/s

Signed-off-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
v3 --> v4:
  - no blank line change.

v2 --> v3:
  - use a property of NFC node to enable/disable NFC write via sram.

 .../devicetree/bindings/mtd/atmel-nand.txt         |    2 +
 drivers/mtd/nand/atmel_nand.c                      |  106 +++++++++++++++++++-
 2 files changed, 103 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index 6a267cb..da78e22 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -35,6 +35,8 @@ Optional properties:
     - reg : should specify the address and size used for NFC command registers,
             NFC registers and NFC Sram. NFC Sram address and size can be absent
             if don't want to use it.
+  - Optional properties:
+    - atmel,write-by-sram: boolean to enable NFC write by sram.
 
 Examples:
 nand0: nand at 40000000,0 {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2e272a7..12c8a38 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -97,12 +97,14 @@ struct atmel_nfc {
 	void __iomem		*sram_bank0;
 	dma_addr_t		sram_bank0_phys;
 	bool			use_nfc_sram;
+	bool			write_by_sram;
 
 	bool			is_initialized;
 	struct completion	comp_nfc;
 
 	/* Point to the sram bank which include readed data via NFC */
 	void __iomem		*data_in_sram;
+	bool			will_write_sram;
 };
 static struct atmel_nfc	nand_nfc;
 
@@ -269,6 +271,16 @@ static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
 		*t++ = readl_relaxed(s++);
 }
 
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+	int i;
+	u32 __iomem *t = trg;
+	const u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		writel_relaxed(*s++, t++);
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
@@ -390,7 +402,11 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 		dma_dst_addr = phys_addr;
 	} else {
 		dma_src_addr = phys_addr;
-		dma_dst_addr = host->io_phys;
+
+		if (nfc && nfc->write_by_sram)
+			dma_dst_addr = nfc_sram_phys(host);
+		else
+			dma_dst_addr = host->io_phys;
 	}
 
 	tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
@@ -961,9 +977,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 	int i, j;
 	unsigned long end_time;
 
-	pmecc_enable(host, NAND_ECC_WRITE);
-
-	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	if (!host->nfc || !host->nfc->write_by_sram) {
+		pmecc_enable(host, NAND_ECC_WRITE);
+		chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	}
 
 	end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
 	while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
@@ -1804,6 +1821,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_RNDIN:
 		nfcwr = NFCADDR_CMD_NFCWR;
+		if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
+			dataen = NFCADDR_CMD_DATAEN;
 		break;
 	default:
 		break;
@@ -1848,6 +1867,68 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
 	}
 }
 
+static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t offset, int data_len, const uint8_t *buf,
+			int oob_required, int page, int cached, int raw)
+{
+	int cfg, len;
+	int status = 0;
+	struct atmel_nand_host *host = chip->priv;
+	void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
+
+	/* Subpage write is not supported */
+	if (offset || (data_len < mtd->writesize))
+		return -EINVAL;
+
+	cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
+	len = mtd->writesize;
+
+	if (unlikely(raw)) {
+		len += mtd->oobsize;
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
+	} else
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
+
+	/* Copy page data to sram that will write to nand via NFC */
+	if (use_dma) {
+		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
+			/* Fall back to use cpu copy */
+			memcpy32_toio(sram, buf, len);
+	} else {
+		memcpy32_toio(sram, buf, len);
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+		/*
+		 * When use NFC sram, need set up PMECC before send
+		 * NAND_CMD_SEQIN command. Since when the nand command
+		 * is sent, nfc will do transfer from sram and nand.
+		 */
+		pmecc_enable(host, NAND_ECC_WRITE);
+
+	host->nfc->will_write_sram = true;
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+	host->nfc->will_write_sram = false;
+
+	if (likely(!raw))
+		/* Need to write ecc into oob */
+		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+	if (status < 0)
+		return status;
+
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
+
+	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+		status = chip->errstat(mtd, chip, FL_WRITING, status, page);
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
 static int nfc_sram_init(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd->priv;
@@ -1890,10 +1971,20 @@ static int nfc_sram_init(struct mtd_info *mtd)
 
 	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
 
+	host->nfc->will_write_sram = false;
 	nfc_set_sram_bank(host, 0);
 
-	dev_info(host->dev, "Using NFC Sram read\n");
+	/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
+	if (host->nfc->write_by_sram) {
+		if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
+				chip->ecc.mode == NAND_ECC_NONE)
+			chip->write_page = nfc_sram_write_page;
+		else
+			host->nfc->write_by_sram = false;
+	}
 
+	dev_info(host->dev, "Using NFC Sram read %s\n",
+			host->nfc->write_by_sram ? "and write" : "");
 	return 0;
 }
 
@@ -2162,6 +2253,11 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
 		} else {
 			nfc->use_nfc_sram = true;
 			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+
+			if (pdev->dev.of_node)
+				nfc->write_by_sram = of_property_read_bool(
+						pdev->dev.of_node,
+						"atmel,write-by-sram");
 		}
 	}
 
-- 
1.7.9.5



From josh.wu at atmel.com  Wed Jun 19 02:23:17 2013
From: josh.wu at atmel.com (Josh Wu)
Date: Wed, 19 Jun 2013 14:23:17 +0800
Subject: [PATCH 6/6] mtd: ofpart: add compatible check for child nodes
In-Reply-To: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
Message-ID: <1371622997-26303-7-git-send-email-josh.wu@atmel.com>

In case that the nand device will support some features like Nand Flash
Controller, we want to make the sub feature as a sub node of nand device.

Use such organization it is easy to enable/disable feature, also it is back
compatible and more readable.

If the sub-node has a compatible property then it is a driver not partition.

Signed-off-by: Josh Wu <josh.wu at atmel.com>
---
v3 --> v4:
  - remove the 'len' parameter, just use NULL.
  - refine the commit message.
  - also add a NOTE in devicetree/bindings/mtd/partition.txt.

 .../devicetree/bindings/mtd/partition.txt          |    1 +
 drivers/mtd/ofpart.c                               |   13 ++++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
index 9315ac9..8e5557d 100644
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
+NOTE: if the sub-node has a compatible string, then it is not a partition.
 
 #address-cells & #size-cells must both be present in the mtd device. There are
 two valid values for both:
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 553d6d6..30fcea1 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -20,6 +20,10 @@
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 
+static bool node_has_compatible(struct device_node *pp)
+{
+	return of_get_property(pp, "compatible", NULL);
+}
 static int parse_ofpart_partitions(struct mtd_info *master,
 				   struct mtd_partition **pparts,
 				   struct mtd_part_parser_data *data)
@@ -40,8 +44,12 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 	/* First count the subnodes */
 	pp = NULL;
 	nr_parts = 0;
-	while ((pp = of_get_next_child(node, pp)))
+	while ((pp = of_get_next_child(node, pp))) {
+		if (node_has_compatible(pp))
+			continue;
+
 		nr_parts++;
+	}
 
 	if (nr_parts == 0)
 		return 0;
@@ -57,6 +65,9 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 		int len;
 		int a_cells, s_cells;
 
+		if (node_has_compatible(pp))
+			continue;
+
 		reg = of_get_property(pp, "reg", &len);
 		if (!reg) {
 			nr_parts--;
-- 
1.7.9.5



From kamlakant.patel at broadcom.com  Wed Jun 19 03:39:12 2013
From: kamlakant.patel at broadcom.com (Kamlakant Patel)
Date: Wed, 19 Jun 2013 13:09:12 +0530
Subject: [PATCH] MTD: Micron SPINAND Driver support
In-Reply-To: <A9FA7AA17969164DBE492D9DACF1594C0258AD25@ntxsjombx02.micron.com>
References: <A9FA7AA17969164DBE492D9DACF1594C0258AD25@ntxsjombx02.micron.com>
Message-ID: <20130619073854.GA14077@kpatel.netlogicmircro.com>

On Mon, May 24, 2010 at 09:54:00PM -0000, Mona Anonuevo (manonuevo) wrote:
> 
> This patch adds support for Micron SPINAND via MTD.
> 
> 
> Signed-off-by: Mona Anonuevo (manonuevo at micron.com)
> Signed-off-by: Tuan Nguyen (tqnguyen at micron.com)
> ----
>  drivers/mtd/Kconfig               |    2 
>  drivers/mtd/Makefile              |    2 
>  drivers/mtd/spinand/Kconfig       |   25 +
>  drivers/mtd/spinand/Makefile      |   10 
>  drivers/mtd/spinand/spinand_lld.c |  760
> ++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/spinand/spinand_mtd.c |  728
> ++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h       |  160 ++++++++
>  7 files changed, 1687 insertions(+)
> 

I do not see this driver in Linux kernel yet. Is there any plan to merge it?
We are using this chip on our Netlogic XLP board and we have some updates to
this driver. If you are not planning to merge it to upstream, can we move it
to the staging tree for now?

> PATCH FOLLOWS
> Kernel Version:  Linux 2.6.33.20
> diff -urN linux-2.6.33.20-orig/drivers/mtd/Kconfig
> linux-2.6.33.20/drivers/mtd/Kconfig
> --- linux-2.6.33.20-orig/drivers/mtd/Kconfig	2010-04-01
> 16:02:33.000000000 -0700
> +++ linux-2.6.33.20/drivers/mtd/Kconfig	2010-05-19 04:28:06.000000000
> -0700
> @@ -325,6 +325,8 @@
>  
>  source "drivers/mtd/onenand/Kconfig"
>  
> +source "drivers/mtd/spinand/Kconfig"
> +
>  source "drivers/mtd/lpddr/Kconfig"
>  
>  source "drivers/mtd/ubi/Kconfig"
> diff -urN linux-2.6.33.20-orig/drivers/mtd/Makefile
> linux-2.6.33.20/drivers/mtd/Makefile
> --- linux-2.6.33.20-orig/drivers/mtd/Makefile	2010-04-01
> 16:02:33.000000000 -0700
> +++ linux-2.6.33.20/drivers/mtd/Makefile	2010-05-19
> 04:28:06.000000000 -0700
> @@ -31,4 +31,6 @@
>  
>  obj-y		+= chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
>  
> +obj-y		+= spinand/ 
> +
>  obj-$(CONFIG_MTD_UBI)		+= ubi/
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/Kconfig
> linux-2.6.33.20/drivers/mtd/spinand/Kconfig
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/Kconfig	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/Kconfig	2010-05-19
> 04:28:06.000000000 -0700
> @@ -0,0 +1,25 @@
> +#
> +# linux/drivers/mtd/spinand/Kconfig
> +#
> +
> +menuconfig MTD_SPINAND
> +	tristate "SPINAND Device Support"
> +	depends on MTD
> +	help
> +	  This enables support for accessing Micron SPI NAND flash
> +	  devices.
> +
> +if MTD_SPINAND
> +
> +config MTD_SPINAND_ONDIEECC
> +	bool "Use SPINAND internal ECC"
> +	help
> +	 Internel ECC
> +
> +config MTD_SPINAND_SWECC
> +	bool "Use software ECC"
> +	depends on MTD_NAND
> +	help
> +	 software ECC
> +
> +endif
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/Makefile
> linux-2.6.33.20/drivers/mtd/spinand/Makefile
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/Makefile	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/Makefile	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,10 @@
> +#
> +# Makefile for the SPI NAND MTD
> +#
> +
> +# Core functionality.
> +obj-$(CONFIG_MTD_SPINAND)		+= spinand.o
> +
> +spinand-objs := spinand_mtd.o spinand_lld.o
> +
> +
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_lld.c
> linux-2.6.33.20/drivers/mtd/spinand/spinand_lld.c
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_lld.c
> 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/spinand_lld.c	2010-05-19
> 03:56:51.000000000 -0700
> @@ -0,0 +1,760 @@
> +/*
> +spinand_lld.c
> +
> +Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This program is free software; you can redistribute it and/or
> +modify it under the terms of the GNU General Public License
> +as published by the Free Software Foundation; either version 2
> +of the License, or (at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +*/
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/mutex.h>
> +#include <linux/math64.h>
> +
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/mtd/spinand.h>
> +
> +#include <linux/spi/spi.h>
> +
> +#define mu_spi_nand_driver_version
> "Beagle-MTD_01.00_Linux2.6.33_20100507"
> +#define SPI_NAND_MICRON_DRIVER_KEY 0x1233567
> +
> +/**********************************************************************
> ******/
> +
> +/**
> +   OOB area specification layout:  Total 32 available free bytes.
> +*/
> +static struct nand_ecclayout spinand_oob_64 = {
> +	.eccbytes = 24,
> +	.eccpos = {
> +		   1, 2, 3, 4, 5, 6,
> +		   17, 18, 19, 20, 21, 22,
> +		   33, 34, 35, 36, 37, 38,
> +		   49, 50, 51, 52, 53, 54, },
> +	.oobavail = 32,
> +	.oobfree = {
> +		{.offset = 8,
> +		 .length = 8},
> +		{.offset = 24,
> +		 .length = 8},
> +		{.offset = 40,
> +		 .length = 8},
> +		{.offset = 56,
> +		 .length = 8}, }
> +};
> +/**
> + * spinand_cmd - to process a command to send to the SPI Nand
> + * 
> + * Description:
> + *    Set up the command buffer to send to the SPI controller.
> + *    The command buffer has to initized to 0
> + */
> +int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
> +{
> +	int					ret;
> +	struct spi_message	message;
> +	struct spi_transfer		x[4];
> +	u8 dummy = 0xff;
> +
> +
> +	spi_message_init(&message);
> +	memset(x, 0, sizeof x);
> +	
> +	x[0].len = 1;
> +	x[0].tx_buf = &cmd->cmd;
> +	spi_message_add_tail(&x[0], &message);
> +	
> +	if (cmd->n_addr)
> +	{
> +		x[1].len = cmd->n_addr;
> +		x[1].tx_buf = cmd->addr;
> +		spi_message_add_tail(&x[1], &message);
> +	}
> +
> +	if (cmd->n_dummy)
> +	{
> +		x[2].len = cmd->n_dummy;
> +		x[2].tx_buf = &dummy;
> +		spi_message_add_tail(&x[2], &message);		
> +	}
> +
> +	if (cmd->n_tx)
> +	{
> +		x[3].len = cmd->n_tx;
> +		x[3].tx_buf = cmd->tx_buf;
> +		spi_message_add_tail(&x[3], &message);		
> +	}
> +
> +	if (cmd->n_rx)
> +	{
> +		x[3].len = cmd->n_rx;
> +		x[3].rx_buf = cmd->rx_buf;
> +		spi_message_add_tail(&x[3], &message);	
> +	}
> +	
> +	ret = spi_sync(spi, &message);
> +
> +	return ret; 
> +}
> +
> +/**
> + * spinand_reset- send reset command "0xff" to the Nand device
> + * 
> + * Description:
> + *    Reset the SPI Nand with the reset command 0xff
> + */
> +static int spinand_reset(struct spi_device *spi_nand)
> +{
> +	struct spinand_cmd cmd = {0};
> +
> +	cmd.cmd = CMD_RESET;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +/**
> + * spinand_read_id- Read SPI Nand ID
> + * 
> + * Description:
> + *    Read ID: read two ID bytes from the SPI Nand device
> + */
> +static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +
> +	
> +	cmd.cmd = CMD_READ_ID;
> +	cmd.n_dummy = 1;
> +	cmd.n_rx = 2;
> +	cmd.rx_buf = id;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d reading id\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +/**
> + * spinand_lock_block- send write register 0x1f command to the Nand
> device
> + * 
> + * Description:
> + *    After power up, all the Nand blocks are locked.  This function
> allows
> + *    one to unlock the blocks, and so it can be wriiten or erased.
> + */
> +static int spinand_lock_block(struct spi_device *spi_nand, struct
> spinand_info *info, u8 lock)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_WRITE_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_BLOCK_LOCK;
> +	cmd.n_tx = 1;
> +	cmd.tx_buf = &lock;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d lock block\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +/**
> + * spinand_read_status- send command 0xf to the SPI Nand status
> register
> + * 
> + * Description:
> + *    After read, write, or erase, the Nand device is expected to set
> the busy status.
> + *    This function is to allow reading the status of the command:
> read, write, and erase.
> + *    Once the status turns to be ready, the other status bits also are
> valid status bits.
> + */
> +static int spinand_read_status(struct spi_device *spi_nand, struct
> spinand_info *info, u8 *status)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_READ_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_STATUS;
> +	cmd.n_rx = 1;
> +	cmd.rx_buf = status;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +				(int) retval);
> +		return retval;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * spinand_get_otp- send command 0xf to read the SPI Nand OTP register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_get_otp(struct spi_device *spi_nand, struct
> spinand_info *info, u8* otp)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_READ_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_OTP;
> +	cmd.n_rx = 1;
> +	cmd.rx_buf = otp;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d get otp\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +
> +/**
> + * spinand_set_otp- send command 0x1f to write the SPI Nand OTP
> register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_set_otp(struct spi_device *spi_nand, struct
> spinand_info *info, u8* otp)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_WRITE_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_OTP;
> +	cmd.n_tx = 1;
> +	cmd.tx_buf = otp;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d set otp\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;
> +}
> +
> +/**
> + * sspinand_enable_ecc- send command 0x1f to write the SPI Nand OTP
> register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_enable_ecc(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	ssize_t retval;
> +	u8 otp = 0;
> +	
> +	retval = spinand_get_otp(spi_nand, info, &otp);
> +
> +	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
> +	{
> +		return 0;
> +	}
> +	else
> +	{
> +		otp |= OTP_ECC_MASK;
> +		retval = spinand_set_otp(spi_nand, info, &otp);
> +		retval = spinand_get_otp(spi_nand, info, &otp);
> +		return retval;
> +	}
> +}
> +
> +static int spinand_disable_ecc(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	ssize_t retval;
> +	u8 otp = 0;
> +	
> +	retval = spinand_get_otp(spi_nand, info, &otp);
> +
> +
> +	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
> +	{
> +		otp &= ~OTP_ECC_MASK;
> +		retval = spinand_set_otp(spi_nand, info, &otp);
> +		retval = spinand_get_otp(spi_nand, info, &otp);
> +		return retval;
> +	}
> +	else
> +	{
> +		return 0;
> +	}
> +}
> +
> +/**
> + * sspinand_write_enable- send command 0x06 to enable write or erase
> the Nand cells
> + * 
> + * Description:
> + *   Before write and erase the Nand cells, the write enable has to be
> set.
> + *   After the write or erase, the write enable bit is automatically
> cleared( status register bit 2 )
> + *   Set the bit 2 of the status register has the same effect
> + */
> +static int spinand_write_enable(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	struct spinand_cmd cmd = {0};
> +
> +	cmd.cmd = CMD_WR_ENABLE;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +static int spinand_read_page_to_cache(struct spi_device *spi_nand,
> struct spinand_info *info, u16 page_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = page_id;
> +
> +	cmd.cmd = CMD_READ;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_read_from_cache- send command 0x03 to read out the data from
> the cache register( 2112 bytes max )
> + * 
> + * Description:
> + *   The read can specify 1 to 2112 bytes of data read at the
> coresponded locations.
> + *   No tRd delay.
> + */
> +static int spinand_read_from_cache(struct spi_device *spi_nand, struct
> spinand_info *info, u16 byte_id, u16 len, u8* rbuf)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 column;
> +
> +	column = byte_id;
> +
> +	cmd.cmd = CMD_READ_RDM;
> +	cmd.n_addr = 2;
> +	cmd.addr[0] = (u8)((column&0xff00)>>8);
> +	cmd.addr[1] = (u8)(column&0x00ff);
> +	cmd.n_dummy = 1;
> +	cmd.n_rx = len;
> +	cmd.rx_buf = rbuf;
> +	
> +	return spinand_cmd(spi_nand, &cmd);	
> +}
> +
> +/**
> + * spinand_read_page-to read a page with:
> + * @page_id: the physical page number
> + * @offset:  the location from 0 to 2111
> + * @len:     number of bytes to read
> + * @rbuf:    read buffer to hold @len bytes
> + *
> + * Description:
> + *   The read icludes two commands to the Nand: 0x13 and 0x03 commands
> + *   Poll to read status to wait for tRD time.
> + */
> +static int spinand_read_page(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* rbuf)
> +{
> +	ssize_t retval;
> +	u8 status = 0;
> +	
> +	retval = spinand_read_page_to_cache(spi_nand, info, page_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +			if ((status & STATUS_ECC_MASK) ==
> STATUS_ECC_ERROR)
> +			{
> +				dev_err(&spi_nand->dev, "ecc error,
> page=%d\n", page_id);
> +				if (spi_nand ==
> SPI_NAND_MICRON_DRIVER_KEY)
> +					printk(KERN_INFO "Error:
> reformat or erase your device. \n"); 
> +				else
> +				return -1;
> +			}
> +			break;
> +		}
> +	}
> +
> +	retval = spinand_read_from_cache(spi_nand, info, offset, len,
> rbuf);
> +	return 0;
> +		
> +}
> +
> +/**
> + * spinand_program_data_to_cache--to write a page to cache with:
> + * @byte_id: the location to write to the cache
> + * @len:     number of bytes to write
> + * @rbuf:    read buffer to hold @len bytes
> + *
> + * Description:
> + *   The write command used here is 0x84--indicating that the cache is
> not cleared first.
> + *   Since it is writing the data to cache, there is no tPROG time.
> + */
> +static int spinand_program_data_to_cache(struct spi_device *spi_nand,
> struct spinand_info *info, u16 byte_id, u16 len, u8* wbuf)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 column;
> +
> +	column = byte_id;
> +
> +	cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
> +	cmd.n_addr = 2;
> +	cmd.addr[0] = (u8)((column&0xff00)>>8);
> +	cmd.addr[1] = (u8)(column&0x00ff);
> +	cmd.n_tx = len;
> +	cmd.tx_buf = wbuf;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_program_execute--to write a page from cache to the Nand
> array with:
> + * @page_id: the physical page location to write the page.
> + *
> + * Description:
> + *   The write command used here is 0x10--indicating the cache is
> writing to the Nand array.
> + *   Need to wait for tPROG time to finish the transaction.
> + */
> +static int spinand_program_execute(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = page_id;
> +
> +	cmd.cmd = CMD_PROG_PAGE_EXC;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_program_page--to write a page with:
> + * @page_id: the physical page location to write the page.
> + * @offset:  the location from the cache starting from 0 to 2111
> + * @len:     the number of bytes to write 
> + * @wbuf:    the buffer to hold the number of bytes
> + *
> + * Description:
> + *   The commands used here are 0x06, 0x84, and 0x10--indicating that
> the write enable is first
> + *   sent, the write cache command, and the write execute command
> + *   Poll to wait for the tPROG time to finish the transaction.
> + */
> +static int spinand_program_page(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* wbuf)
> +{
> +	ssize_t retval;
> +	u8 status = 0;
> +
> +	retval = spinand_write_enable(spi_nand, info);
> +	
> +	retval = spinand_program_data_to_cache(spi_nand, info, offset,
> len, wbuf);
> +
> +	retval = spinand_program_execute(spi_nand, info, page_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +
> +			if ((status & STATUS_P_FAIL_MASK) ==
> STATUS_P_FAIL)
> +			{
> +				dev_err(&spi_nand->dev, "program error,
> page=%d\n", page_id);
> +				return -1;
> +			}
> +			else
> +				break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * spinand_erase_block_erase--to erase a page with:
> + * @block_id: the physical block location to erase.
> + *
> + * Description:
> + *   The command used here is 0xd8--indicating an erase command to
> erase one block--64 pages
> + *   Need to wait for tERS.
> + */
> +static int spinand_erase_block_erase(struct spi_device *spi_nand,
> struct spinand_info *info, u16 block_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = block_id << 6;
> +	cmd.cmd = CMD_ERASE_BLK;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);	
> +}
> +
> +/**
> + * spinand_erase_block--to erase a page with:
> + * @block_id: the physical block location to erase.
> + *
> + * Description:
> + *   The commands used here are 0x06 and 0xd8--indicating an erase
> command to erase one block--64 pages
> + *   It will first to enable the write enable bit ( 0x06 command ), and
> then send the 0xd8 erase command
> + *   Poll to wait for the tERS time to complete the tranaction.
> + */
> +static int spinand_erase_block(struct spi_device *spi_nand, struct
> spinand_info *info, u16 block_id)
> +{
> +	ssize_t retval;
> +	u8 status= 0;
> +
> +	retval = spinand_write_enable(spi_nand, info);
> +	
> +	retval = spinand_erase_block_erase(spi_nand, info, block_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +			if ((status & STATUS_E_FAIL_MASK) ==
> STATUS_E_FAIL)
> +			{
> +				dev_err(&spi_nand->dev, "erase error,
> block=%d\n", block_id);
> +				return -1;
> +			}
> +			else
> +				break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> +* spinand_get_info: get NAND info, from read id or const value 
> +
> + * Description:
> + *   To set up the device parameters.
> + */
> +static int spinand_get_info(struct spi_device *spi_nand, struct
> spinand_info *info, u8* id)
> +{
> +	if (id[0]==0x2C && (id[1]==0x11 || id[1]==0x12 || id[1]==0x13))
> +	{
> +		info->mid = id[0];
> +		info->did = id[1];
> +		info->name = "MT29F1G01ZAC";
> +		info->nand_size = (1024 * 64 * 2112);
> +		info->usable_size = (1024 * 64 * 2048);
> +		info->block_size = (2112*64);
> +		info->block_main_size = (2048*64);
> +		info->block_num_per_chip = 1024;
> +		info->page_size = 2112;
> +		info->page_main_size = 2048;
> +		info->page_spare_size = 64;
> +		info->page_num_per_block = 64;
> +
> +		info->block_shift = 17;
> +		info->block_mask = 0x1ffff;
> +
> +		info->page_shift = 11;
> +		info->page_mask = 0x7ff;
> +		
> +		info->ecclayout = &spinand_oob_64;
> +	}	
> +	
> +	return 0;
> +}
> +
> +/**
> + * spinand_probe - [spinand Interface] 
> +* @spi_nand: registered device driver.
> + *
> + * Description:
> + *   To set up the device driver parameters to make the device
> available.
> + */
> +static int __devinit spinand_probe(struct spi_device *spi_nand)
> +{
> +	ssize_t retval;
> +	struct mtd_info *mtd;
> +	struct spinand_chip *chip; 
> +	struct spinand_info *info;
> +	u8 id[2]= {0};
> +	
> +	retval = spinand_reset(spi_nand);
> +	retval = spinand_reset(spi_nand);
> +	retval = spinand_read_id(spi_nand, (u8*)&id);
> +	if (id[0]==0 && id[1]==0)
> +	{
> +		printk(KERN_INFO "SPINAND: read id error! 0x%02x,
> 0x%02x!\n", id[0], id[1]); 
> +		return 0;
> +	}
> +
> +	info  = kzalloc(sizeof(struct spinand_info), GFP_KERNEL);
> +	if (!info)
> +		return -ENOMEM;
> +	
> +	retval = spinand_get_info(spi_nand, info, (u8*)&id);
> +	printk(KERN_INFO "SPINAND: 0x%02x, 0x%02x, %s\n", id[0], id[1],
> info->name); 
> +	printk(KERN_INFO "%s\n", mu_spi_nand_driver_version);
> +	retval = spinand_lock_block(spi_nand, info, BL_ALL_UNLOCKED);
> +
> +#ifdef CONFIG_MTD_SPINAND_ONDIEECC
> +	retval = spinand_enable_ecc(spi_nand, info);
> +#else
> +	retval = spinand_disable_ecc(spi_nand, info);
> +#endif
> +
> +	chip  = kzalloc(sizeof(struct spinand_chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->spi_nand = spi_nand;
> +	chip->info = info;
> +	chip->reset = spinand_reset;
> +	chip->read_id = spinand_read_id;
> +	chip->read_page = spinand_read_page;
> +	chip->program_page = spinand_program_page;
> +	chip->erase_block = spinand_erase_block;
> +
> +	chip->buf = kzalloc(info->page_size, GFP_KERNEL);
> +	if (!chip->buf)
> +		return -ENOMEM;
> +
> +	chip->oobbuf = kzalloc(info->ecclayout->oobavail, GFP_KERNEL);
> +	if (!chip->oobbuf)
> +		return -ENOMEM;
> +
> +	mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
> +	if (!mtd)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(&spi_nand->dev, mtd);
> +	
> +	mtd->priv = chip;
> +
> +	retval = spinand_mtd(mtd);
> +	
> +	return retval;
> +}
> +
> +/**
> + * __devexit spinand_remove--Remove the device driver
> + * @spi: the spi device.
> + *
> + * Description:
> + *   To remove the device driver parameters and free up allocated
> memories.
> + */
> +static int __devexit spinand_remove(struct spi_device *spi)
> +{
> +	struct mtd_info *mtd;
> +	struct spinand_chip *chip; 
> +
> +	DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev));
> +
> +	mtd = dev_get_drvdata(&spi->dev);
> +	
> +	spinand_mtd_release(mtd);
> +
> +	chip = mtd->priv;
> +	
> +	kfree(chip->info);
> +	kfree(chip->buf);
> +	kfree(chip->oobbuf);
> +	kfree(chip);
> +	kfree(mtd);
> +	
> +	return 0;
> +}
> +
> +/**
> + * Device name structure description
> +*/
> +static struct spi_driver spinand_driver = {
> +	.driver = {
> +		.name		= "spi_nand",
> +		.bus		= &spi_bus_type,
> +		.owner		= THIS_MODULE,
> +	},
> +
> +	.probe		= spinand_probe,
> +	.remove		= __devexit_p(spinand_remove),
> +};
> +
> +/**
> + * Device driver registration
> +*/
> +static int __init spinand_init(void)
> +{
> +	return spi_register_driver(&spinand_driver);
> +}
> +
> +/**
> + * unregister Device driver.
> +*/
> +static void __exit spinand_exit(void)
> +{
> +	spi_unregister_driver(&spinand_driver);
> +}
> +
> +module_init(spinand_init);
> +module_exit(spinand_exit);
> +
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Henry Pan <hspan at micron.com>");
> +MODULE_DESCRIPTION("SPI NAND driver code");
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_mtd.c
> linux-2.6.33.20/drivers/mtd/spinand/spinand_mtd.c
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_mtd.c
> 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/spinand_mtd.c	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,728 @@
> +/*
> +spinand_mtd.c
> +
> +Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This program is free software; you can redistribute it and/or
> +modify it under the terms of the GNU General Public License
> +as published by the Free Software Foundation; either version 2
> +of the License, or (at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +*/
> +
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/jiffies.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/mtd/spinand.h>
> +#include <linux/mtd/nand_ecc.h>
> +
> +/**
> + * spinand_get_device - [GENERIC] Get chip for selected access
> + * @param mtd		MTD device structure
> + * @param new_state	the state which is requested
> + *
> + * Get the device and lock it for exclusive access
> + */
> +#define mu_spi_nand_driver_version
> "Beagle-MTD_01.00_Linux2.6.33_20100507"
> +static int spinand_get_device(struct mtd_info *mtd, int new_state)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +	DECLARE_WAITQUEUE(wait, current);
> +
> +	/*
> +	 * Grab the lock and see if the device is available
> +	 */
> +	while (1) {
> +		spin_lock(&this->chip_lock);
> +		if (this->state == FL_READY) {
> +			this->state = new_state;
> +			spin_unlock(&this->chip_lock);
> +			break;
> +		}
> +		if (new_state == FL_PM_SUSPENDED) {
> +			spin_unlock(&this->chip_lock);
> +			return (this->state == FL_PM_SUSPENDED) ? 0 :
> -EAGAIN;
> +		}
> +		set_current_state(TASK_UNINTERRUPTIBLE);
> +		add_wait_queue(&this->wq, &wait);
> +		spin_unlock(&this->chip_lock);
> +		schedule();
> +		remove_wait_queue(&this->wq, &wait);
> +	}
> +	return 0;
> +}
> +
> +/**
> + * spinand_release_device - [GENERIC] release chip
> + * @param mtd		MTD device structure
> + *
> + * Deselect, release chip lock and wake up anyone waiting on the device
> + */
> +static void spinand_release_device(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +
> +	/* Release the chip */
> +	spin_lock(&this->chip_lock);
> +	this->state = FL_READY;
> +	wake_up(&this->wq);
> +	spin_unlock(&this->chip_lock);
> +}
> +
> +#ifdef CONFIG_MTD_SPINAND_SWECC 
> +static void spinand_calculate_ecc(struct mtd_info *mtd)
> +{
> +	int i; 
> +	int eccsize = 512;
> +	int eccbytes = 3;
> +	int eccsteps = 4;
> +	int ecctotal = 12;
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +	unsigned char *p = chip->buf;
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
> +
> +	for (i = 0; i < ecctotal; i++)
> +		chip->buf[info->page_main_size +
> info->ecclayout->eccpos[i]] = chip->ecc_calc[i];
> +}
> +
> +static int spinand_correct_data(struct mtd_info *mtd)
> +{
> +	int i; 
> +	int eccsize = 512;
> +	int eccbytes = 3;
> +	int eccsteps = 4;
> +	int ecctotal = 12;
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +	unsigned char *p = chip->buf;
> +	int errcode = 0;
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
> +
> +	for (i = 0; i < ecctotal; i++)
> +		chip->ecc_code[i] = chip->buf[info->page_main_size +
> info->ecclayout->eccpos[i]];
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +	{
> +		int stat;
> +		
> +		stat = __nand_correct_data(p, &chip->ecc_code[i],
> &chip->ecc_calc[i], eccsize);
> +		if (stat < 0)
> +		{
> +			errcode = -1;
> +		}
> +		else if (stat == 1)
> +		{
> +			errcode = 1;
> +		}
> +	}
> +
> +	return errcode;
> +}
> +#endif
> +
> +static int spinand_read_ops(struct mtd_info *mtd, loff_t from,
> +			  struct mtd_oob_ops *ops)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	int page_id, page_offset, page_num, oob_num;
> +
> +	int count;
> +	int main_ok, main_left, main_offset;
> +	int oob_ok, oob_left;
> +	
> +	signed int retval;
> +	signed int errcode=0;
> +
> +	if (!chip->buf)
> +		return -1;
> +
> +	page_id = from >> info->page_shift;
> +
> +	/* for main data */
> +	page_offset = from & info->page_mask;
> +	page_num = (page_offset + ops->len + info->page_main_size -1 ) /
> info->page_main_size;
> +
> +	/* for oob */
> +	oob_num = (ops->ooblen + info->ecclayout->oobavail -1) /
> info->ecclayout->oobavail;
> +
> +	count = 0;
> +
> +	main_left = ops->len;
> +	main_ok = 0;
> +	main_offset = page_offset;
> +
> +	oob_left = ops->ooblen;
> +	oob_ok = 0;
> +
> +	while (1)
> +	{
> +		if (count < page_num || count < oob_num) 
> +		{
> +			memset(chip->buf, 0, info->page_size); 
> +			retval = chip->read_page(spi_nand, info, page_id
> + count, 0, info->page_size, chip->buf);
> +			if (retval != 0)
> +			{
> +				errcode = -1;
> +				printk(KERN_INFO "spinand_read_ops:
> fail, page=%d!\n", page_id);
> +
> +				return errcode;
> +			}
> +		}
> +		else
> +		{
> +			break;
> +		}
> +	
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			int size;
> +			
> +#ifdef CONFIG_MTD_SPINAND_SWECC
> +			retval = spinand_correct_data(mtd);
> +			if (retval == -1)
> +				printk(KERN_INFO "SWECC uncorrectable
> error! page=%x\n", page_id+count); 
> +			else if (retval == 1)
> +				printk(KERN_INFO "SWECC 1 bit error,
> corrected! page=%x\n", page_id+count); 
> +
> +#endif
> +
> +			if ((main_offset + main_left) <
> info->page_main_size)
> +			{
> +				size = main_left;
> +			}
> +			else
> +			{
> +				size = info->page_main_size -
> main_offset;
> +			}
> +			
> +			memcpy (ops->datbuf + main_ok, chip->buf, size);
> +
> +			main_ok += size;
> +			main_left -= size;
> +			main_offset = 0;
> +
> +			ops->retlen = main_ok;
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			int size;
> +			int offset, len, temp;
> +		
> +			/* repack spare to oob */
> +			memset(chip->oobbuf, 0,
> info->ecclayout->oobavail);
> +
> +			temp = 0;
> +			offset = info->ecclayout->oobfree[0].offset;
> +			len = info->ecclayout->oobfree[0].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +	
> +			temp += len;
> +			offset = info->ecclayout->oobfree[1].offset;
> +			len = info->ecclayout->oobfree[1].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +	
> +			temp += len;
> +			offset = info->ecclayout->oobfree[2].offset;
> +			len = info->ecclayout->oobfree[2].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[3].offset;
> +			len = info->ecclayout->oobfree[3].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +
> +			/* copy oobbuf to ops oobbuf */
> +			if (oob_left < info->ecclayout->oobavail) 
> +			{
> +				size = oob_left;
> +			}
> +			else
> +			{
> +				size = info->ecclayout->oobavail;
> +			}
> +
> +			memcpy (ops->oobbuf + oob_ok, chip->oobbuf,
> size);
> +
> +			oob_ok += size;
> +			oob_left -= size;
> +
> +			ops->oobretlen = oob_ok;
> +		}
> +
> +		count++;
> +	}
> +	return errcode;
> +}
> +
> +static int spinand_write_ops(struct mtd_info *mtd, loff_t to,
> +			  struct mtd_oob_ops *ops)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	int page_id, page_offset, page_num, oob_num;
> +
> +	int count;
> +
> +	int main_ok, main_left, main_offset;
> +	int oob_ok, oob_left;
> +	
> +	signed int retval;
> +	signed int errcode=0;
> +
> +	if (!chip->buf)
> +		return -1;
> +
> +	page_id = to >> info->page_shift;
> +
> +	/* for main data */
> +	page_offset = to & info->page_mask;
> +	page_num = (page_offset + ops->len + info->page_main_size -1 ) /
> info->page_main_size;
> +
> +	/* for oob */
> +	oob_num = (ops->ooblen + info->ecclayout->oobavail -1) /
> info->ecclayout->oobavail;
> +
> +	count = 0;
> +
> +	main_left = ops->len;
> +	main_ok = 0;
> +	main_offset = page_offset;
> +
> +	oob_left = ops->ooblen;
> +	oob_ok = 0;
> +
> +	while (1)
> +	{
> +		if (count < page_num || count < oob_num) 
> +		{
> +			memset(chip->buf, 0xFF, info->page_size); 
> +		}
> +		else
> +		{
> +			break; 
> +		}
> +
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			int size;
> +
> +			if ((main_offset + main_left) <
> info->page_main_size)
> +			{
> +				size = main_left;
> +			}
> +			else
> +			{
> +				size = info->page_main_size -
> main_offset;
> +			}
> +
> +			memcpy (chip->buf, ops->datbuf + main_ok, size);
> +			
> +			main_ok += size;
> +			main_left -= size;
> +			main_offset = 0;
> +			
> +#ifdef CONFIG_MTD_SPINAND_SWECC 
> +			spinand_calculate_ecc(mtd);
> +#endif
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			int size;
> +			int offset, len, temp;
> +
> +			memset(chip->oobbuf, 0xFF,
> info->ecclayout->oobavail);
> +
> +			if (oob_left < info->ecclayout->oobavail) 
> +			{
> +				size = oob_left;
> +			}
> +			else
> +			{
> +				size = info->ecclayout->oobavail;
> +			}
> +
> +			memcpy (chip->oobbuf, ops->oobbuf + oob_ok,
> size);
> +
> +			oob_ok += size;
> +			oob_left -= size;
> +
> +			/* repack oob to spare */
> +			temp = 0;
> +			offset = info->ecclayout->oobfree[0].offset;
> +			len = info->ecclayout->oobfree[0].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +		
> +			temp += len;
> +			offset = info->ecclayout->oobfree[1].offset;
> +			len = info->ecclayout->oobfree[1].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[2].offset;
> +			len = info->ecclayout->oobfree[2].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[3].offset;
> +			len = info->ecclayout->oobfree[3].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +		
> +		}
> +
> +		if (count < page_num || count < oob_num) 
> +		{
> +
> +			retval = chip->program_page(spi_nand, info,
> page_id + count, 0, info->page_size, chip->buf);
> +			if (retval != 0)
> +			{
> +				errcode = -1;
> +				printk(KERN_INFO "spinand_write_ops:
> fail, page=%d!\n", page_id);
> +
> +				return errcode;
> +			}
> +		}
> +
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			ops->retlen = main_ok;
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			ops->oobretlen = oob_ok;
> +		}
> +
> +		count++;
> +
> +	}
> +
> +	return errcode;
> +}
> +
> +static int spinand_read(struct mtd_info *mtd, loff_t from, size_t len,
> +	size_t *retlen, u_char *buf)
> +{
> +	struct mtd_oob_ops ops = {0};
> +	int ret;
> +	
> +	/* Do not allow reads past end of device */
> +	if ((from + len) > mtd->size)
> +		return -EINVAL;
> +
> +	if (!len)
> +		return 0;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	ops.len = len;
> +	ops.datbuf = buf;
> +
> +	ret = spinand_read_ops(mtd, from, &ops);
> + 
> + 	*retlen = ops.retlen;
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_write(struct mtd_info *mtd, loff_t to, size_t len,
> +	size_t *retlen, const u_char *buf)
> +{
> +	struct mtd_oob_ops ops = {0};
> +	int ret;
> +	
> +	/* Do not allow reads past end of device */
> +	if ((to + len) > mtd->size)
> +		return -EINVAL;
> +	if (!len)
> +		return 0;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	ops.len = len;
> +	ops.datbuf = (uint8_t *)buf;
> +
> +	ret =  spinand_write_ops(mtd, to, &ops);
> +
> +	*retlen = ops.retlen;
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_read_oob(struct mtd_info *mtd, loff_t from,
> +			  struct mtd_oob_ops *ops)
> +{
> +	int ret;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	ret = spinand_read_ops(mtd, from, ops);
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_write_oob(struct mtd_info *mtd, loff_t to,
> +			  struct mtd_oob_ops *ops)
> +{
> +	int ret;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	ret = spinand_write_ops(mtd, to, ops);
> +	
> +	spinand_release_device(mtd);
> +	
> +	return ret;
> +}
> +
> +/**
> + * spinand_erase - [MTD Interface] erase block(s)
> + * @param mtd		MTD device structure
> + * @param instr		erase instruction
> + *
> + * Erase one ore more blocks
> + */
> +static int spinand_erase(struct mtd_info *mtd, struct erase_info
> *instr)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id, block_num, count;
> +	signed int retval=0;
> +	signed int errcode=0;
> +
> +	DEBUG(MTD_DEBUG_LEVEL3, "spinand_erase: start = 0x%012llx, len =
> %llu\n",
> +	      (unsigned long long)instr->addr, (unsigned long
> long)instr->len);
> +
> +	/* check address align on block boundary */
> +	if (instr->addr & (info->block_main_size - 1)) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: Unaligned
> address\n");
> +		return -EINVAL;
> +	}
> +
> +	if (instr->len & (info->block_main_size - 1)) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: "
> +		      "Length not block aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Do not allow erase past end of device */
> +	if ((instr->len + instr->addr) > info->usable_size) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: "
> +		      "Erase past end of device\n");
> +		return -EINVAL;
> +	}
> +
> +	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;	
> +
> +	
> +	/* Grab the lock and see if the device is available */
> +	spinand_get_device(mtd, FL_ERASING);
> +
> +	block_id = instr->addr >> info->block_shift;
> +	block_num = instr->len >> info->block_shift; 
> +	count = 0;
> +	
> +	while (count < block_num )
> +	{
> +		retval = chip->erase_block(spi_nand, info,
> block_id+count);
> +
> +		if (retval!=0)
> +		{
> +			retval = chip->erase_block(spi_nand, info,
> block_id+count);
> +			if (retval!=0)
> +			{
> +				printk(KERN_INFO "spinand_erase: fail,
> block=%d!\n", block_id+count);
> +				errcode = -1;
> +			}
> +		}
> +		count++;
> +	}
> +	
> +	if (errcode == 0)
> +	{
> +		instr->state = MTD_ERASE_DONE;
> +	}
> +	
> +	/* Deselect and wake up anyone waiting on the device */
> +	spinand_release_device(mtd);
> +
> +	/* Do call back function */
> +	if(instr->callback)
> +		instr->callback(instr);
> +	
> +	return errcode;
> +}
> +
> +/**
> + * spinand_sync - [MTD Interface] sync
> + * @param mtd		MTD device structure
> + *
> + * Sync is actually a wait for chip ready function
> + */
> +static void spinand_sync(struct mtd_info *mtd)
> +{
> +	DEBUG(MTD_DEBUG_LEVEL3, "spinand_sync: called\n");
> +
> +	/* Grab the lock and see if the device is available */
> +	spinand_get_device(mtd, FL_SYNCING);
> +
> +	/* Release it and go back */
> +	spinand_release_device(mtd);
> +}
> +
> +static int spinand_block_isbad(struct mtd_info *mtd, loff_t ofs)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id;
> +	u8 is_bad = 0x00;
> +	u8 ret = 0;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	block_id = ofs >> info->block_shift;
> +
> +	chip->read_page(spi_nand, info,
> block_id*info->page_num_per_block, info->page_main_size, 1, &is_bad);
> +
> +	if (is_bad != 0xFF)
> +	{
> +		ret =  1;	
> +	}
> +
> +	spinand_release_device(mtd);
> +
> +	return ret; 
> +}
> +
> +/**
> + * spinand_block_markbad - [MTD Interface] Mark bad block
> + * @param mtd		MTD device structure
> + * @param ofs       Bad block number
> + */
> +static int spinand_block_markbad(struct mtd_info *mtd, loff_t ofs)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id;
> +	u8 is_bad = 0x00; 
> +	u8 ret = 0;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	block_id = ofs >> info->block_shift;
> +
> +	chip->program_page(spi_nand, info,
> block_id*info->page_num_per_block, info->page_main_size, 1, &is_bad);
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +
> +/**
> + * spinand_suspend - [MTD Interface] Suspend the spinand flash
> + * @param mtd		MTD device structure
> + */
> +static int spinand_suspend(struct mtd_info *mtd)
> +{
> +	return spinand_get_device(mtd, FL_PM_SUSPENDED);
> +}
> +
> +/**
> + * spinand_resume - [MTD Interface] Resume the spinand flash
> + * @param mtd		MTD device structure
> + */
> +static void spinand_resume(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +
> +	if (this->state == FL_PM_SUSPENDED)
> +		spinand_release_device(mtd);
> +	else
> +		printk(KERN_ERR "resume() called for the chip which is
> not"
> +				"in suspended state\n");
> +}
> +
> +/**
> + * spinand_mtd - add MTD device with parameters
> + * @param mtd		MTD device structure
> + *
> + * Add MTD device with parameters.
> + */
> +int spinand_mtd(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +
> +	chip->state = FL_READY;
> +	init_waitqueue_head(&chip->wq);
> +	spin_lock_init(&chip->chip_lock);
> +
> +	mtd->name = info->name;
> +	mtd->size = info->usable_size;
> +	mtd->erasesize = info->block_main_size;
> +	mtd->writesize = info->page_main_size;
> +	mtd->oobsize = info->ecclayout->oobavail;
> +	mtd->owner = THIS_MODULE;
> +	mtd->type = MTD_NANDFLASH;
> +	mtd->flags = MTD_CAP_NANDFLASH;
> +
> +	mtd->ecclayout = info->ecclayout;
> +
> +	mtd->erase = spinand_erase;
> +	mtd->point = NULL;
> +	mtd->unpoint = NULL;
> +	mtd->read = spinand_read;
> +	mtd->write = spinand_write;
> +	mtd->read_oob = spinand_read_oob;
> +	mtd->write_oob = spinand_write_oob;
> +	mtd->sync = spinand_sync;
> +	mtd->lock = NULL;
> +	mtd->unlock = NULL;
> +	mtd->suspend = spinand_suspend;
> +	mtd->resume = spinand_resume;
> +	mtd->block_isbad = spinand_block_isbad;
> +	mtd->block_markbad = spinand_block_markbad;
> +	
> +	return add_mtd_device(mtd) == 1 ? -ENODEV : 0;
> +}
> +
> +void spinand_mtd_release(struct mtd_info *mtd)
> +{
> +	del_mtd_device(mtd);
> +}
> +
> +EXPORT_SYMBOL_GPL(spinand_mtd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Henry Pan <hspan at micron.com>");
> +MODULE_DESCRIPTION("SPI NAND driver code");
> diff -urN linux-2.6.33.20-orig/include/linux/mtd/spinand.h
> linux-2.6.33.20/include/linux/mtd/spinand.h
> --- linux-2.6.33.20-orig/include/linux/mtd/spinand.h	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/include/linux/mtd/spinand.h	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,160 @@
> +/*
> + *  linux/include/linux/mtd/spinand.h
> + *
> + Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This software is licensed under the terms of the GNU General Public
> +License version 2, as published by the Free Software Foundation, and
> +may be copied, distributed, and modified under those terms.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> + *  Henry Pan <hspan at micron.com>
> + *
> + *  based on nand.h
> + */
> +#ifndef __LINUX_MTD_SPI_NAND_H
> +#define __LINUX_MTD_SPI_NAND_H
> +
> +#include <linux/wait.h>
> +#include <linux/spinlock.h>
> +#include <linux/mtd/mtd.h>
> +
> +/* cmd */
> +#define CMD_READ				0x13
> +#define CMD_READ_RDM			0x03
> +#define CMD_PROG_PAGE_CLRCACHE	0x02
> +#define CMD_PROG_PAGE			0x84
> +#define CMD_PROG_PAGE_EXC		0x10
> +#define CMD_ERASE_BLK			0xd8
> +#define CMD_WR_ENABLE			0x06
> +#define CMD_WR_DISABLE			0x04
> +#define CMD_READ_ID			0x9f
> +#define CMD_RESET				0xff
> +#define CMD_READ_REG			0x0f
> +#define CMD_WRITE_REG			0x1f
> +
> +/* feature/ status reg */
> +#define REG_BLOCK_LOCK		0xa0
> +#define REG_OTP				0xb0
> +#define REG_STATUS			0xc0/* timing */
> +
> +/* status */
> +#define STATUS_OIP_MASK		0x01
> +#define STATUS_READY		0 << 0
> +#define STATUS_BUSY			1 << 0
> +
> +#define STATUS_E_FAIL_MASK	0x04
> +#define STATUS_E_FAIL		1 << 2
> +
> +#define STATUS_P_FAIL_MASK 	0x08
> +#define STATUS_P_FAIL		1 << 3
> +
> +#define STATUS_ECC_MASK 	0x30
> +#define STATUS_ECC_1BIT_CORRECTED	1 << 4
> +#define STATUS_ECC_ERROR			2 << 4
> +#define STATUS_ECC_RESERVED			3 << 4
> +
> +
> +/*ECC enable defines*/
> +#define OTP_ECC_MASK		0x10
> +#define OTP_ECC_OFF			0
> +#define OTP_ECC_ON			1
> +
> +#define ECC_DISABLED
> +#define ECC_IN_NAND   
> +#define ECC_SOFT
> +
> +/* block lock */
> +#define BL_ALL_LOCKED      0x38 
> +#define BL_1_2_LOCKED      0x30
> +#define BL_1_4_LOCKED      0x28
> +#define BL_1_8_LOCKED      0x20
> +#define BL_1_16_LOCKED     0x18
> +#define BL_1_32_LOCKED     0x10
> +#define BL_1_64_LOCKED     0x08
> +#define BL_ALL_UNLOCKED    0
> +
> +/**********************************************************************
> ******/
> +
> +struct spinand_info {
> +	u8		mid;
> +	u8		did;
> +	char		*name;
> +	u64		nand_size;
> +	u64		usable_size;
> +
> +	u32		block_size;
> +	u32		block_main_size;
> +	/*u32		block_spare_size; */
> +	u16		block_num_per_chip;
> +	
> +	u16		page_size;
> +	u16		page_main_size;
> +	u16		page_spare_size;
> +	u16		page_num_per_block;
> +	
> +	u8		block_shift;
> +	u32		block_mask;
> +
> +	u8		page_shift;
> +	u16		page_mask;
> +
> +	struct nand_ecclayout *ecclayout;
> +};
> +
> +typedef enum {
> +	FL_READY,
> +	FL_READING,
> +	FL_WRITING,
> +	FL_ERASING,
> +	FL_SYNCING,
> +	FL_LOCKING,
> +	FL_RESETING,
> +	FL_OTPING,
> +	FL_PM_SUSPENDED,
> +} spinand_state_t;
> +	
> +struct spinand_chip { /* used for multi chip */
> +	spinlock_t		chip_lock;
> +	wait_queue_head_t wq;	
> +	spinand_state_t	state;
> +	struct spi_device	*spi_nand;
> +	struct spinand_info *info;
> +	/*struct mtd_info	*mtd; */
> +
> +	int (*reset) (struct spi_device *spi_nand);
> +	int (*read_id) (struct spi_device *spi_nand, u8* id);
> +	int (*read_page) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* rbuf);
> +	int (*program_page) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* wbuf);
> +	int (*erase_block) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 block_id);
> +
> +	u8 *buf;
> +	u8 *oobbuf; /* temp buffer */
> +
> +
> +#ifdef CONFIG_MTD_SPINAND_SWECC
> +	u8 ecc_calc[12];
> +	u8 ecc_code[12];
> +#endif
> +};
> +
> +struct spinand_cmd {
> +	u8 cmd;
> +	unsigned n_addr;	
> +	u8 addr[3];
> +	unsigned n_dummy;
> +	unsigned n_tx;	
> +	u8 *tx_buf;
> +	unsigned n_rx;
> +	u8 *rx_buf;
> +};
> +
> +extern int spinand_mtd(struct mtd_info *mtd);
> +extern void spinand_mtd_release(struct mtd_info *mtd);
> +
> +
> +#endif /* __LINUX_MTD_SPI_NAND_H */

Thanks,
Kamlakant Patel



From brian.foster at maximintegrated.com  Wed Jun 19 10:14:53 2013
From: brian.foster at maximintegrated.com (Brian Foster)
Date: Wed, 19 Jun 2013 16:14:53 +0200
Subject: [Q] Using Micron 4-bit on-die ECC with v2.6.36 kernel?
Message-ID: <17588192.75Agdljyqk@laclwks004>


 Our current reference Linux kernel for the MAX32590 (JIBE)
 is based on v2.6.36.  (Unfortunately, upgrading to a more
 recent version is not within the timeframe for solving the
 current problem.)  Our recent reference boards use one of
 those Micron NAND chips with an on-die 4-bit ECC, which we
 have basically ignored:  To-date, we have simply used the
 usual 1-bit ECC (i.e., living dangerously!).

 This must change, and indeed we now have a case on my desk
 where, had we been using the on-die ECC, it would have saved
 us a ton of grief.  The problem is our kernel version is far
 too old to take advantage of any of the recent-ish work for
 on-die ECC.

 Hence, I am looking into the possibility of adding on-die ECC
 support to our JIBE controller driver specifically for such
 NAND chips (or at least the specific Micron NAND chip on the
 reference boards).  Broadly, pretending JIBE's H/W directly
 supports on-die ECC, but actually doing the work in the driver.
 A similar trick we played in the past (bitwise-inverted ECC
 (now obsoleted and long-removed from the driver)) suggests
 this is not too difficult.

 I am looking for hints (suggestions), gotchas (warnings),
 and/or any examples of similar (or other plausible) approaches.
 Or for something I am overlooking in (or available for) kernels
 of approximately the vintage we are using.

Thanks & cheers!
	-blf-

p.s.  At the present time, I am not too interested in the
     problem of converting existing boards.  This MAY change
     as the scope and details of the solution become more
     apparent.

-- 
Brian Foster
Principal MTS, Software        |  La Ciotat, France
Maxim Integrated               |  http://www.maximintegrated.com/



From sergei.shtylyov at cogentembedded.com  Wed Jun 19 10:15:40 2013
From: sergei.shtylyov at cogentembedded.com (Sergei Shtylyov)
Date: Wed, 19 Jun 2013 18:15:40 +0400
Subject: [PATCH 2/6] mtd: atmel_nand: replace pmecc enable code with one
 function.
In-Reply-To: <1371622997-26303-3-git-send-email-josh.wu@atmel.com>
References: <1371622997-26303-1-git-send-email-josh.wu@atmel.com>
 <1371622997-26303-3-git-send-email-josh.wu@atmel.com>
Message-ID: <51C1BD0C.2040008@cogentembedded.com>

Hello.

On 19-06-2013 10:23, Josh Wu wrote:

> Signed-off-by: Josh Wu <josh.wu at atmel.com>
> Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> ---
>   drivers/mtd/nand/atmel_nand.c |   40 +++++++++++++++++++++++++---------------
>   1 file changed, 25 insertions(+), 15 deletions(-)

> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index d39f364..cb8362e 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -754,6 +754,29 @@ normal_check:
>   	return total_err;
>   }
>
> +static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
> +{
> +	u32 val;

    Other functions have empty line after the declaration.

> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> +	val = pmecc_readl_relaxed(host->ecc, CFG);
> +
> +	if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
> +		dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
> +		return;
> +	}
> +
> +	if (ecc_op == NAND_ECC_READ)
> +		pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
> +			| PMECC_CFG_AUTO_ENABLE);
> +	else
> +		pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
> +			& ~PMECC_CFG_AUTO_ENABLE);
> +
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
> +	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
> +}
> +

WBR, Sergei



From manonuevo at micron.com  Wed Jun 19 12:41:46 2013
From: manonuevo at micron.com (Mona Anonuevo (manonuevo))
Date: Wed, 19 Jun 2013 16:41:46 +0000
Subject: [PATCH] MTD: Micron SPINAND Driver support
In-Reply-To: <20130619073854.GA14077@kpatel.netlogicmircro.com>
References: <A9FA7AA17969164DBE492D9DACF1594C0258AD25@ntxsjombx02.micron.com>
 <20130619073854.GA14077@kpatel.netlogicmircro.com>
Message-ID: <814C696C26B5294C8E153E846D6EF6944688DD12@NTXBOIMBX03.micron.com>

Hello!
Yes we move it to the staging tree.
Thank you,
Mona Anonuevo

-----Original Message-----
From: Kamlakant Patel [mailto:kamlakant.patel at broadcom.com] 
Sent: Wednesday, June 19, 2013 12:39 AM
To: Mona Anonuevo (manonuevo)
Cc: linux-mtd at lists.infradead.org
Subject: Re: [PATCH] MTD: Micron SPINAND Driver support

On Mon, May 24, 2010 at 09:54:00PM -0000, Mona Anonuevo (manonuevo) wrote:
> 
> This patch adds support for Micron SPINAND via MTD.
> 
> 
> Signed-off-by: Mona Anonuevo (manonuevo at micron.com)
> Signed-off-by: Tuan Nguyen (tqnguyen at micron.com)
> ----
>  drivers/mtd/Kconfig               |    2 
>  drivers/mtd/Makefile              |    2 
>  drivers/mtd/spinand/Kconfig       |   25 +
>  drivers/mtd/spinand/Makefile      |   10 
>  drivers/mtd/spinand/spinand_lld.c |  760
> ++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/spinand/spinand_mtd.c |  728
> ++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h       |  160 ++++++++
>  7 files changed, 1687 insertions(+)
> 

I do not see this driver in Linux kernel yet. Is there any plan to merge it?
We are using this chip on our Netlogic XLP board and we have some updates to
this driver. If you are not planning to merge it to upstream, can we move it
to the staging tree for now?

> PATCH FOLLOWS
> Kernel Version:  Linux 2.6.33.20
> diff -urN linux-2.6.33.20-orig/drivers/mtd/Kconfig
> linux-2.6.33.20/drivers/mtd/Kconfig
> --- linux-2.6.33.20-orig/drivers/mtd/Kconfig	2010-04-01
> 16:02:33.000000000 -0700
> +++ linux-2.6.33.20/drivers/mtd/Kconfig	2010-05-19 04:28:06.000000000
> -0700
> @@ -325,6 +325,8 @@
>  
>  source "drivers/mtd/onenand/Kconfig"
>  
> +source "drivers/mtd/spinand/Kconfig"
> +
>  source "drivers/mtd/lpddr/Kconfig"
>  
>  source "drivers/mtd/ubi/Kconfig"
> diff -urN linux-2.6.33.20-orig/drivers/mtd/Makefile
> linux-2.6.33.20/drivers/mtd/Makefile
> --- linux-2.6.33.20-orig/drivers/mtd/Makefile	2010-04-01
> 16:02:33.000000000 -0700
> +++ linux-2.6.33.20/drivers/mtd/Makefile	2010-05-19
> 04:28:06.000000000 -0700
> @@ -31,4 +31,6 @@
>  
>  obj-y		+= chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
>  
> +obj-y		+= spinand/ 
> +
>  obj-$(CONFIG_MTD_UBI)		+= ubi/
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/Kconfig
> linux-2.6.33.20/drivers/mtd/spinand/Kconfig
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/Kconfig	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/Kconfig	2010-05-19
> 04:28:06.000000000 -0700
> @@ -0,0 +1,25 @@
> +#
> +# linux/drivers/mtd/spinand/Kconfig
> +#
> +
> +menuconfig MTD_SPINAND
> +	tristate "SPINAND Device Support"
> +	depends on MTD
> +	help
> +	  This enables support for accessing Micron SPI NAND flash
> +	  devices.
> +
> +if MTD_SPINAND
> +
> +config MTD_SPINAND_ONDIEECC
> +	bool "Use SPINAND internal ECC"
> +	help
> +	 Internel ECC
> +
> +config MTD_SPINAND_SWECC
> +	bool "Use software ECC"
> +	depends on MTD_NAND
> +	help
> +	 software ECC
> +
> +endif
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/Makefile
> linux-2.6.33.20/drivers/mtd/spinand/Makefile
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/Makefile	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/Makefile	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,10 @@
> +#
> +# Makefile for the SPI NAND MTD
> +#
> +
> +# Core functionality.
> +obj-$(CONFIG_MTD_SPINAND)		+= spinand.o
> +
> +spinand-objs := spinand_mtd.o spinand_lld.o
> +
> +
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_lld.c
> linux-2.6.33.20/drivers/mtd/spinand/spinand_lld.c
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_lld.c
> 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/spinand_lld.c	2010-05-19
> 03:56:51.000000000 -0700
> @@ -0,0 +1,760 @@
> +/*
> +spinand_lld.c
> +
> +Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This program is free software; you can redistribute it and/or
> +modify it under the terms of the GNU General Public License
> +as published by the Free Software Foundation; either version 2
> +of the License, or (at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +*/
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/mutex.h>
> +#include <linux/math64.h>
> +
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/mtd/spinand.h>
> +
> +#include <linux/spi/spi.h>
> +
> +#define mu_spi_nand_driver_version
> "Beagle-MTD_01.00_Linux2.6.33_20100507"
> +#define SPI_NAND_MICRON_DRIVER_KEY 0x1233567
> +
> +/**********************************************************************
> ******/
> +
> +/**
> +   OOB area specification layout:  Total 32 available free bytes.
> +*/
> +static struct nand_ecclayout spinand_oob_64 = {
> +	.eccbytes = 24,
> +	.eccpos = {
> +		   1, 2, 3, 4, 5, 6,
> +		   17, 18, 19, 20, 21, 22,
> +		   33, 34, 35, 36, 37, 38,
> +		   49, 50, 51, 52, 53, 54, },
> +	.oobavail = 32,
> +	.oobfree = {
> +		{.offset = 8,
> +		 .length = 8},
> +		{.offset = 24,
> +		 .length = 8},
> +		{.offset = 40,
> +		 .length = 8},
> +		{.offset = 56,
> +		 .length = 8}, }
> +};
> +/**
> + * spinand_cmd - to process a command to send to the SPI Nand
> + * 
> + * Description:
> + *    Set up the command buffer to send to the SPI controller.
> + *    The command buffer has to initized to 0
> + */
> +int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
> +{
> +	int					ret;
> +	struct spi_message	message;
> +	struct spi_transfer		x[4];
> +	u8 dummy = 0xff;
> +
> +
> +	spi_message_init(&message);
> +	memset(x, 0, sizeof x);
> +	
> +	x[0].len = 1;
> +	x[0].tx_buf = &cmd->cmd;
> +	spi_message_add_tail(&x[0], &message);
> +	
> +	if (cmd->n_addr)
> +	{
> +		x[1].len = cmd->n_addr;
> +		x[1].tx_buf = cmd->addr;
> +		spi_message_add_tail(&x[1], &message);
> +	}
> +
> +	if (cmd->n_dummy)
> +	{
> +		x[2].len = cmd->n_dummy;
> +		x[2].tx_buf = &dummy;
> +		spi_message_add_tail(&x[2], &message);		
> +	}
> +
> +	if (cmd->n_tx)
> +	{
> +		x[3].len = cmd->n_tx;
> +		x[3].tx_buf = cmd->tx_buf;
> +		spi_message_add_tail(&x[3], &message);		
> +	}
> +
> +	if (cmd->n_rx)
> +	{
> +		x[3].len = cmd->n_rx;
> +		x[3].rx_buf = cmd->rx_buf;
> +		spi_message_add_tail(&x[3], &message);	
> +	}
> +	
> +	ret = spi_sync(spi, &message);
> +
> +	return ret; 
> +}
> +
> +/**
> + * spinand_reset- send reset command "0xff" to the Nand device
> + * 
> + * Description:
> + *    Reset the SPI Nand with the reset command 0xff
> + */
> +static int spinand_reset(struct spi_device *spi_nand)
> +{
> +	struct spinand_cmd cmd = {0};
> +
> +	cmd.cmd = CMD_RESET;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +/**
> + * spinand_read_id- Read SPI Nand ID
> + * 
> + * Description:
> + *    Read ID: read two ID bytes from the SPI Nand device
> + */
> +static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +
> +	
> +	cmd.cmd = CMD_READ_ID;
> +	cmd.n_dummy = 1;
> +	cmd.n_rx = 2;
> +	cmd.rx_buf = id;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d reading id\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +/**
> + * spinand_lock_block- send write register 0x1f command to the Nand
> device
> + * 
> + * Description:
> + *    After power up, all the Nand blocks are locked.  This function
> allows
> + *    one to unlock the blocks, and so it can be wriiten or erased.
> + */
> +static int spinand_lock_block(struct spi_device *spi_nand, struct
> spinand_info *info, u8 lock)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_WRITE_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_BLOCK_LOCK;
> +	cmd.n_tx = 1;
> +	cmd.tx_buf = &lock;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d lock block\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +/**
> + * spinand_read_status- send command 0xf to the SPI Nand status
> register
> + * 
> + * Description:
> + *    After read, write, or erase, the Nand device is expected to set
> the busy status.
> + *    This function is to allow reading the status of the command:
> read, write, and erase.
> + *    Once the status turns to be ready, the other status bits also are
> valid status bits.
> + */
> +static int spinand_read_status(struct spi_device *spi_nand, struct
> spinand_info *info, u8 *status)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_READ_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_STATUS;
> +	cmd.n_rx = 1;
> +	cmd.rx_buf = status;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +				(int) retval);
> +		return retval;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * spinand_get_otp- send command 0xf to read the SPI Nand OTP register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_get_otp(struct spi_device *spi_nand, struct
> spinand_info *info, u8* otp)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_READ_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_OTP;
> +	cmd.n_rx = 1;
> +	cmd.rx_buf = otp;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d get otp\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;	
> +}
> +
> +
> +/**
> + * spinand_set_otp- send command 0x1f to write the SPI Nand OTP
> register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_set_otp(struct spi_device *spi_nand, struct
> spinand_info *info, u8* otp)
> +{
> +	struct spinand_cmd cmd = {0};
> +	ssize_t retval;
> +	
> +	cmd.cmd = CMD_WRITE_REG;
> +	cmd.n_addr = 1;
> +	cmd.addr[0] = REG_OTP;
> +	cmd.n_tx = 1;
> +	cmd.tx_buf = otp;
> +	
> +	retval = spinand_cmd(spi_nand, &cmd);
> +
> +	if (retval != 0) {
> +		dev_err(&spi_nand->dev, "error %d set otp\n",
> +				(int) retval);
> +		return retval;
> +	}
> +	
> +	return 0;
> +}
> +
> +/**
> + * sspinand_enable_ecc- send command 0x1f to write the SPI Nand OTP
> register
> + * 
> + * Description:
> + *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
> + *   Enable chip internal ECC, set the bit to 1
> + *   Disable chip internal ECC, clear the bit to 0
> + */
> +static int spinand_enable_ecc(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	ssize_t retval;
> +	u8 otp = 0;
> +	
> +	retval = spinand_get_otp(spi_nand, info, &otp);
> +
> +	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
> +	{
> +		return 0;
> +	}
> +	else
> +	{
> +		otp |= OTP_ECC_MASK;
> +		retval = spinand_set_otp(spi_nand, info, &otp);
> +		retval = spinand_get_otp(spi_nand, info, &otp);
> +		return retval;
> +	}
> +}
> +
> +static int spinand_disable_ecc(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	ssize_t retval;
> +	u8 otp = 0;
> +	
> +	retval = spinand_get_otp(spi_nand, info, &otp);
> +
> +
> +	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
> +	{
> +		otp &= ~OTP_ECC_MASK;
> +		retval = spinand_set_otp(spi_nand, info, &otp);
> +		retval = spinand_get_otp(spi_nand, info, &otp);
> +		return retval;
> +	}
> +	else
> +	{
> +		return 0;
> +	}
> +}
> +
> +/**
> + * sspinand_write_enable- send command 0x06 to enable write or erase
> the Nand cells
> + * 
> + * Description:
> + *   Before write and erase the Nand cells, the write enable has to be
> set.
> + *   After the write or erase, the write enable bit is automatically
> cleared( status register bit 2 )
> + *   Set the bit 2 of the status register has the same effect
> + */
> +static int spinand_write_enable(struct spi_device *spi_nand, struct
> spinand_info *info)
> +{
> +	struct spinand_cmd cmd = {0};
> +
> +	cmd.cmd = CMD_WR_ENABLE;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +static int spinand_read_page_to_cache(struct spi_device *spi_nand,
> struct spinand_info *info, u16 page_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = page_id;
> +
> +	cmd.cmd = CMD_READ;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_read_from_cache- send command 0x03 to read out the data from
> the cache register( 2112 bytes max )
> + * 
> + * Description:
> + *   The read can specify 1 to 2112 bytes of data read at the
> coresponded locations.
> + *   No tRd delay.
> + */
> +static int spinand_read_from_cache(struct spi_device *spi_nand, struct
> spinand_info *info, u16 byte_id, u16 len, u8* rbuf)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 column;
> +
> +	column = byte_id;
> +
> +	cmd.cmd = CMD_READ_RDM;
> +	cmd.n_addr = 2;
> +	cmd.addr[0] = (u8)((column&0xff00)>>8);
> +	cmd.addr[1] = (u8)(column&0x00ff);
> +	cmd.n_dummy = 1;
> +	cmd.n_rx = len;
> +	cmd.rx_buf = rbuf;
> +	
> +	return spinand_cmd(spi_nand, &cmd);	
> +}
> +
> +/**
> + * spinand_read_page-to read a page with:
> + * @page_id: the physical page number
> + * @offset:  the location from 0 to 2111
> + * @len:     number of bytes to read
> + * @rbuf:    read buffer to hold @len bytes
> + *
> + * Description:
> + *   The read icludes two commands to the Nand: 0x13 and 0x03 commands
> + *   Poll to read status to wait for tRD time.
> + */
> +static int spinand_read_page(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* rbuf)
> +{
> +	ssize_t retval;
> +	u8 status = 0;
> +	
> +	retval = spinand_read_page_to_cache(spi_nand, info, page_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +			if ((status & STATUS_ECC_MASK) ==
> STATUS_ECC_ERROR)
> +			{
> +				dev_err(&spi_nand->dev, "ecc error,
> page=%d\n", page_id);
> +				if (spi_nand ==
> SPI_NAND_MICRON_DRIVER_KEY)
> +					printk(KERN_INFO "Error:
> reformat or erase your device. \n"); 
> +				else
> +				return -1;
> +			}
> +			break;
> +		}
> +	}
> +
> +	retval = spinand_read_from_cache(spi_nand, info, offset, len,
> rbuf);
> +	return 0;
> +		
> +}
> +
> +/**
> + * spinand_program_data_to_cache--to write a page to cache with:
> + * @byte_id: the location to write to the cache
> + * @len:     number of bytes to write
> + * @rbuf:    read buffer to hold @len bytes
> + *
> + * Description:
> + *   The write command used here is 0x84--indicating that the cache is
> not cleared first.
> + *   Since it is writing the data to cache, there is no tPROG time.
> + */
> +static int spinand_program_data_to_cache(struct spi_device *spi_nand,
> struct spinand_info *info, u16 byte_id, u16 len, u8* wbuf)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 column;
> +
> +	column = byte_id;
> +
> +	cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
> +	cmd.n_addr = 2;
> +	cmd.addr[0] = (u8)((column&0xff00)>>8);
> +	cmd.addr[1] = (u8)(column&0x00ff);
> +	cmd.n_tx = len;
> +	cmd.tx_buf = wbuf;
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_program_execute--to write a page from cache to the Nand
> array with:
> + * @page_id: the physical page location to write the page.
> + *
> + * Description:
> + *   The write command used here is 0x10--indicating the cache is
> writing to the Nand array.
> + *   Need to wait for tPROG time to finish the transaction.
> + */
> +static int spinand_program_execute(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = page_id;
> +
> +	cmd.cmd = CMD_PROG_PAGE_EXC;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);
> +}
> +
> +/**
> + * spinand_program_page--to write a page with:
> + * @page_id: the physical page location to write the page.
> + * @offset:  the location from the cache starting from 0 to 2111
> + * @len:     the number of bytes to write 
> + * @wbuf:    the buffer to hold the number of bytes
> + *
> + * Description:
> + *   The commands used here are 0x06, 0x84, and 0x10--indicating that
> the write enable is first
> + *   sent, the write cache command, and the write execute command
> + *   Poll to wait for the tPROG time to finish the transaction.
> + */
> +static int spinand_program_page(struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* wbuf)
> +{
> +	ssize_t retval;
> +	u8 status = 0;
> +
> +	retval = spinand_write_enable(spi_nand, info);
> +	
> +	retval = spinand_program_data_to_cache(spi_nand, info, offset,
> len, wbuf);
> +
> +	retval = spinand_program_execute(spi_nand, info, page_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +
> +			if ((status & STATUS_P_FAIL_MASK) ==
> STATUS_P_FAIL)
> +			{
> +				dev_err(&spi_nand->dev, "program error,
> page=%d\n", page_id);
> +				return -1;
> +			}
> +			else
> +				break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * spinand_erase_block_erase--to erase a page with:
> + * @block_id: the physical block location to erase.
> + *
> + * Description:
> + *   The command used here is 0xd8--indicating an erase command to
> erase one block--64 pages
> + *   Need to wait for tERS.
> + */
> +static int spinand_erase_block_erase(struct spi_device *spi_nand,
> struct spinand_info *info, u16 block_id)
> +{
> +	struct spinand_cmd cmd = {0};
> +	u16 row;
> +
> +	row = block_id << 6;
> +	cmd.cmd = CMD_ERASE_BLK;
> +	cmd.n_addr = 3;
> +	cmd.addr[1] = (u8)((row&0xff00)>>8);
> +	cmd.addr[2] = (u8)(row&0x00ff);
> +
> +	return spinand_cmd(spi_nand, &cmd);	
> +}
> +
> +/**
> + * spinand_erase_block--to erase a page with:
> + * @block_id: the physical block location to erase.
> + *
> + * Description:
> + *   The commands used here are 0x06 and 0xd8--indicating an erase
> command to erase one block--64 pages
> + *   It will first to enable the write enable bit ( 0x06 command ), and
> then send the 0xd8 erase command
> + *   Poll to wait for the tERS time to complete the tranaction.
> + */
> +static int spinand_erase_block(struct spi_device *spi_nand, struct
> spinand_info *info, u16 block_id)
> +{
> +	ssize_t retval;
> +	u8 status= 0;
> +
> +	retval = spinand_write_enable(spi_nand, info);
> +	
> +	retval = spinand_erase_block_erase(spi_nand, info, block_id);
> +
> +	while (1)
> +	{
> +		retval = spinand_read_status(spi_nand, info, &status);
> +		if (retval<0) {
> +			dev_err(&spi_nand->dev, "error %d reading status
> register\n",
> +					(int) retval);
> +			return retval;
> +		}
> +
> +		if ((status & STATUS_OIP_MASK) == STATUS_READY)
> +		{
> +			if ((status & STATUS_E_FAIL_MASK) ==
> STATUS_E_FAIL)
> +			{
> +				dev_err(&spi_nand->dev, "erase error,
> block=%d\n", block_id);
> +				return -1;
> +			}
> +			else
> +				break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> +* spinand_get_info: get NAND info, from read id or const value 
> +
> + * Description:
> + *   To set up the device parameters.
> + */
> +static int spinand_get_info(struct spi_device *spi_nand, struct
> spinand_info *info, u8* id)
> +{
> +	if (id[0]==0x2C && (id[1]==0x11 || id[1]==0x12 || id[1]==0x13))
> +	{
> +		info->mid = id[0];
> +		info->did = id[1];
> +		info->name = "MT29F1G01ZAC";
> +		info->nand_size = (1024 * 64 * 2112);
> +		info->usable_size = (1024 * 64 * 2048);
> +		info->block_size = (2112*64);
> +		info->block_main_size = (2048*64);
> +		info->block_num_per_chip = 1024;
> +		info->page_size = 2112;
> +		info->page_main_size = 2048;
> +		info->page_spare_size = 64;
> +		info->page_num_per_block = 64;
> +
> +		info->block_shift = 17;
> +		info->block_mask = 0x1ffff;
> +
> +		info->page_shift = 11;
> +		info->page_mask = 0x7ff;
> +		
> +		info->ecclayout = &spinand_oob_64;
> +	}	
> +	
> +	return 0;
> +}
> +
> +/**
> + * spinand_probe - [spinand Interface] 
> +* @spi_nand: registered device driver.
> + *
> + * Description:
> + *   To set up the device driver parameters to make the device
> available.
> + */
> +static int __devinit spinand_probe(struct spi_device *spi_nand)
> +{
> +	ssize_t retval;
> +	struct mtd_info *mtd;
> +	struct spinand_chip *chip; 
> +	struct spinand_info *info;
> +	u8 id[2]= {0};
> +	
> +	retval = spinand_reset(spi_nand);
> +	retval = spinand_reset(spi_nand);
> +	retval = spinand_read_id(spi_nand, (u8*)&id);
> +	if (id[0]==0 && id[1]==0)
> +	{
> +		printk(KERN_INFO "SPINAND: read id error! 0x%02x,
> 0x%02x!\n", id[0], id[1]); 
> +		return 0;
> +	}
> +
> +	info  = kzalloc(sizeof(struct spinand_info), GFP_KERNEL);
> +	if (!info)
> +		return -ENOMEM;
> +	
> +	retval = spinand_get_info(spi_nand, info, (u8*)&id);
> +	printk(KERN_INFO "SPINAND: 0x%02x, 0x%02x, %s\n", id[0], id[1],
> info->name); 
> +	printk(KERN_INFO "%s\n", mu_spi_nand_driver_version);
> +	retval = spinand_lock_block(spi_nand, info, BL_ALL_UNLOCKED);
> +
> +#ifdef CONFIG_MTD_SPINAND_ONDIEECC
> +	retval = spinand_enable_ecc(spi_nand, info);
> +#else
> +	retval = spinand_disable_ecc(spi_nand, info);
> +#endif
> +
> +	chip  = kzalloc(sizeof(struct spinand_chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->spi_nand = spi_nand;
> +	chip->info = info;
> +	chip->reset = spinand_reset;
> +	chip->read_id = spinand_read_id;
> +	chip->read_page = spinand_read_page;
> +	chip->program_page = spinand_program_page;
> +	chip->erase_block = spinand_erase_block;
> +
> +	chip->buf = kzalloc(info->page_size, GFP_KERNEL);
> +	if (!chip->buf)
> +		return -ENOMEM;
> +
> +	chip->oobbuf = kzalloc(info->ecclayout->oobavail, GFP_KERNEL);
> +	if (!chip->oobbuf)
> +		return -ENOMEM;
> +
> +	mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
> +	if (!mtd)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(&spi_nand->dev, mtd);
> +	
> +	mtd->priv = chip;
> +
> +	retval = spinand_mtd(mtd);
> +	
> +	return retval;
> +}
> +
> +/**
> + * __devexit spinand_remove--Remove the device driver
> + * @spi: the spi device.
> + *
> + * Description:
> + *   To remove the device driver parameters and free up allocated
> memories.
> + */
> +static int __devexit spinand_remove(struct spi_device *spi)
> +{
> +	struct mtd_info *mtd;
> +	struct spinand_chip *chip; 
> +
> +	DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev));
> +
> +	mtd = dev_get_drvdata(&spi->dev);
> +	
> +	spinand_mtd_release(mtd);
> +
> +	chip = mtd->priv;
> +	
> +	kfree(chip->info);
> +	kfree(chip->buf);
> +	kfree(chip->oobbuf);
> +	kfree(chip);
> +	kfree(mtd);
> +	
> +	return 0;
> +}
> +
> +/**
> + * Device name structure description
> +*/
> +static struct spi_driver spinand_driver = {
> +	.driver = {
> +		.name		= "spi_nand",
> +		.bus		= &spi_bus_type,
> +		.owner		= THIS_MODULE,
> +	},
> +
> +	.probe		= spinand_probe,
> +	.remove		= __devexit_p(spinand_remove),
> +};
> +
> +/**
> + * Device driver registration
> +*/
> +static int __init spinand_init(void)
> +{
> +	return spi_register_driver(&spinand_driver);
> +}
> +
> +/**
> + * unregister Device driver.
> +*/
> +static void __exit spinand_exit(void)
> +{
> +	spi_unregister_driver(&spinand_driver);
> +}
> +
> +module_init(spinand_init);
> +module_exit(spinand_exit);
> +
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Henry Pan <hspan at micron.com>");
> +MODULE_DESCRIPTION("SPI NAND driver code");
> diff -urN linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_mtd.c
> linux-2.6.33.20/drivers/mtd/spinand/spinand_mtd.c
> --- linux-2.6.33.20-orig/drivers/mtd/spinand/spinand_mtd.c
> 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/drivers/mtd/spinand/spinand_mtd.c	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,728 @@
> +/*
> +spinand_mtd.c
> +
> +Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This program is free software; you can redistribute it and/or
> +modify it under the terms of the GNU General Public License
> +as published by the Free Software Foundation; either version 2
> +of the License, or (at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +*/
> +
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/jiffies.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/mtd/spinand.h>
> +#include <linux/mtd/nand_ecc.h>
> +
> +/**
> + * spinand_get_device - [GENERIC] Get chip for selected access
> + * @param mtd		MTD device structure
> + * @param new_state	the state which is requested
> + *
> + * Get the device and lock it for exclusive access
> + */
> +#define mu_spi_nand_driver_version
> "Beagle-MTD_01.00_Linux2.6.33_20100507"
> +static int spinand_get_device(struct mtd_info *mtd, int new_state)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +	DECLARE_WAITQUEUE(wait, current);
> +
> +	/*
> +	 * Grab the lock and see if the device is available
> +	 */
> +	while (1) {
> +		spin_lock(&this->chip_lock);
> +		if (this->state == FL_READY) {
> +			this->state = new_state;
> +			spin_unlock(&this->chip_lock);
> +			break;
> +		}
> +		if (new_state == FL_PM_SUSPENDED) {
> +			spin_unlock(&this->chip_lock);
> +			return (this->state == FL_PM_SUSPENDED) ? 0 :
> -EAGAIN;
> +		}
> +		set_current_state(TASK_UNINTERRUPTIBLE);
> +		add_wait_queue(&this->wq, &wait);
> +		spin_unlock(&this->chip_lock);
> +		schedule();
> +		remove_wait_queue(&this->wq, &wait);
> +	}
> +	return 0;
> +}
> +
> +/**
> + * spinand_release_device - [GENERIC] release chip
> + * @param mtd		MTD device structure
> + *
> + * Deselect, release chip lock and wake up anyone waiting on the device
> + */
> +static void spinand_release_device(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +
> +	/* Release the chip */
> +	spin_lock(&this->chip_lock);
> +	this->state = FL_READY;
> +	wake_up(&this->wq);
> +	spin_unlock(&this->chip_lock);
> +}
> +
> +#ifdef CONFIG_MTD_SPINAND_SWECC 
> +static void spinand_calculate_ecc(struct mtd_info *mtd)
> +{
> +	int i; 
> +	int eccsize = 512;
> +	int eccbytes = 3;
> +	int eccsteps = 4;
> +	int ecctotal = 12;
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +	unsigned char *p = chip->buf;
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
> +
> +	for (i = 0; i < ecctotal; i++)
> +		chip->buf[info->page_main_size +
> info->ecclayout->eccpos[i]] = chip->ecc_calc[i];
> +}
> +
> +static int spinand_correct_data(struct mtd_info *mtd)
> +{
> +	int i; 
> +	int eccsize = 512;
> +	int eccbytes = 3;
> +	int eccsteps = 4;
> +	int ecctotal = 12;
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +	unsigned char *p = chip->buf;
> +	int errcode = 0;
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
> +
> +	for (i = 0; i < ecctotal; i++)
> +		chip->ecc_code[i] = chip->buf[info->page_main_size +
> info->ecclayout->eccpos[i]];
> +
> +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> +	{
> +		int stat;
> +		
> +		stat = __nand_correct_data(p, &chip->ecc_code[i],
> &chip->ecc_calc[i], eccsize);
> +		if (stat < 0)
> +		{
> +			errcode = -1;
> +		}
> +		else if (stat == 1)
> +		{
> +			errcode = 1;
> +		}
> +	}
> +
> +	return errcode;
> +}
> +#endif
> +
> +static int spinand_read_ops(struct mtd_info *mtd, loff_t from,
> +			  struct mtd_oob_ops *ops)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	int page_id, page_offset, page_num, oob_num;
> +
> +	int count;
> +	int main_ok, main_left, main_offset;
> +	int oob_ok, oob_left;
> +	
> +	signed int retval;
> +	signed int errcode=0;
> +
> +	if (!chip->buf)
> +		return -1;
> +
> +	page_id = from >> info->page_shift;
> +
> +	/* for main data */
> +	page_offset = from & info->page_mask;
> +	page_num = (page_offset + ops->len + info->page_main_size -1 ) /
> info->page_main_size;
> +
> +	/* for oob */
> +	oob_num = (ops->ooblen + info->ecclayout->oobavail -1) /
> info->ecclayout->oobavail;
> +
> +	count = 0;
> +
> +	main_left = ops->len;
> +	main_ok = 0;
> +	main_offset = page_offset;
> +
> +	oob_left = ops->ooblen;
> +	oob_ok = 0;
> +
> +	while (1)
> +	{
> +		if (count < page_num || count < oob_num) 
> +		{
> +			memset(chip->buf, 0, info->page_size); 
> +			retval = chip->read_page(spi_nand, info, page_id
> + count, 0, info->page_size, chip->buf);
> +			if (retval != 0)
> +			{
> +				errcode = -1;
> +				printk(KERN_INFO "spinand_read_ops:
> fail, page=%d!\n", page_id);
> +
> +				return errcode;
> +			}
> +		}
> +		else
> +		{
> +			break;
> +		}
> +	
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			int size;
> +			
> +#ifdef CONFIG_MTD_SPINAND_SWECC
> +			retval = spinand_correct_data(mtd);
> +			if (retval == -1)
> +				printk(KERN_INFO "SWECC uncorrectable
> error! page=%x\n", page_id+count); 
> +			else if (retval == 1)
> +				printk(KERN_INFO "SWECC 1 bit error,
> corrected! page=%x\n", page_id+count); 
> +
> +#endif
> +
> +			if ((main_offset + main_left) <
> info->page_main_size)
> +			{
> +				size = main_left;
> +			}
> +			else
> +			{
> +				size = info->page_main_size -
> main_offset;
> +			}
> +			
> +			memcpy (ops->datbuf + main_ok, chip->buf, size);
> +
> +			main_ok += size;
> +			main_left -= size;
> +			main_offset = 0;
> +
> +			ops->retlen = main_ok;
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			int size;
> +			int offset, len, temp;
> +		
> +			/* repack spare to oob */
> +			memset(chip->oobbuf, 0,
> info->ecclayout->oobavail);
> +
> +			temp = 0;
> +			offset = info->ecclayout->oobfree[0].offset;
> +			len = info->ecclayout->oobfree[0].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +	
> +			temp += len;
> +			offset = info->ecclayout->oobfree[1].offset;
> +			len = info->ecclayout->oobfree[1].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +	
> +			temp += len;
> +			offset = info->ecclayout->oobfree[2].offset;
> +			len = info->ecclayout->oobfree[2].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[3].offset;
> +			len = info->ecclayout->oobfree[3].length;
> +			memcpy (chip->oobbuf + temp, chip->buf +
> info->page_main_size + offset, len);
> +
> +			/* copy oobbuf to ops oobbuf */
> +			if (oob_left < info->ecclayout->oobavail) 
> +			{
> +				size = oob_left;
> +			}
> +			else
> +			{
> +				size = info->ecclayout->oobavail;
> +			}
> +
> +			memcpy (ops->oobbuf + oob_ok, chip->oobbuf,
> size);
> +
> +			oob_ok += size;
> +			oob_left -= size;
> +
> +			ops->oobretlen = oob_ok;
> +		}
> +
> +		count++;
> +	}
> +	return errcode;
> +}
> +
> +static int spinand_write_ops(struct mtd_info *mtd, loff_t to,
> +			  struct mtd_oob_ops *ops)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	int page_id, page_offset, page_num, oob_num;
> +
> +	int count;
> +
> +	int main_ok, main_left, main_offset;
> +	int oob_ok, oob_left;
> +	
> +	signed int retval;
> +	signed int errcode=0;
> +
> +	if (!chip->buf)
> +		return -1;
> +
> +	page_id = to >> info->page_shift;
> +
> +	/* for main data */
> +	page_offset = to & info->page_mask;
> +	page_num = (page_offset + ops->len + info->page_main_size -1 ) /
> info->page_main_size;
> +
> +	/* for oob */
> +	oob_num = (ops->ooblen + info->ecclayout->oobavail -1) /
> info->ecclayout->oobavail;
> +
> +	count = 0;
> +
> +	main_left = ops->len;
> +	main_ok = 0;
> +	main_offset = page_offset;
> +
> +	oob_left = ops->ooblen;
> +	oob_ok = 0;
> +
> +	while (1)
> +	{
> +		if (count < page_num || count < oob_num) 
> +		{
> +			memset(chip->buf, 0xFF, info->page_size); 
> +		}
> +		else
> +		{
> +			break; 
> +		}
> +
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			int size;
> +
> +			if ((main_offset + main_left) <
> info->page_main_size)
> +			{
> +				size = main_left;
> +			}
> +			else
> +			{
> +				size = info->page_main_size -
> main_offset;
> +			}
> +
> +			memcpy (chip->buf, ops->datbuf + main_ok, size);
> +			
> +			main_ok += size;
> +			main_left -= size;
> +			main_offset = 0;
> +			
> +#ifdef CONFIG_MTD_SPINAND_SWECC 
> +			spinand_calculate_ecc(mtd);
> +#endif
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			int size;
> +			int offset, len, temp;
> +
> +			memset(chip->oobbuf, 0xFF,
> info->ecclayout->oobavail);
> +
> +			if (oob_left < info->ecclayout->oobavail) 
> +			{
> +				size = oob_left;
> +			}
> +			else
> +			{
> +				size = info->ecclayout->oobavail;
> +			}
> +
> +			memcpy (chip->oobbuf, ops->oobbuf + oob_ok,
> size);
> +
> +			oob_ok += size;
> +			oob_left -= size;
> +
> +			/* repack oob to spare */
> +			temp = 0;
> +			offset = info->ecclayout->oobfree[0].offset;
> +			len = info->ecclayout->oobfree[0].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +		
> +			temp += len;
> +			offset = info->ecclayout->oobfree[1].offset;
> +			len = info->ecclayout->oobfree[1].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[2].offset;
> +			len = info->ecclayout->oobfree[2].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +
> +			temp += len;
> +			offset = info->ecclayout->oobfree[3].offset;
> +			len = info->ecclayout->oobfree[3].length;
> +			memcpy (chip->buf + info->page_main_size +
> offset, chip->oobbuf + temp, len);
> +		
> +		}
> +
> +		if (count < page_num || count < oob_num) 
> +		{
> +
> +			retval = chip->program_page(spi_nand, info,
> page_id + count, 0, info->page_size, chip->buf);
> +			if (retval != 0)
> +			{
> +				errcode = -1;
> +				printk(KERN_INFO "spinand_write_ops:
> fail, page=%d!\n", page_id);
> +
> +				return errcode;
> +			}
> +		}
> +
> +		if (count < page_num && ops->datbuf) 
> +		{
> +			ops->retlen = main_ok;
> +		}
> +
> +		if (count < oob_num && ops->oobbuf && chip->oobbuf)
> +		{
> +			ops->oobretlen = oob_ok;
> +		}
> +
> +		count++;
> +
> +	}
> +
> +	return errcode;
> +}
> +
> +static int spinand_read(struct mtd_info *mtd, loff_t from, size_t len,
> +	size_t *retlen, u_char *buf)
> +{
> +	struct mtd_oob_ops ops = {0};
> +	int ret;
> +	
> +	/* Do not allow reads past end of device */
> +	if ((from + len) > mtd->size)
> +		return -EINVAL;
> +
> +	if (!len)
> +		return 0;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	ops.len = len;
> +	ops.datbuf = buf;
> +
> +	ret = spinand_read_ops(mtd, from, &ops);
> + 
> + 	*retlen = ops.retlen;
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_write(struct mtd_info *mtd, loff_t to, size_t len,
> +	size_t *retlen, const u_char *buf)
> +{
> +	struct mtd_oob_ops ops = {0};
> +	int ret;
> +	
> +	/* Do not allow reads past end of device */
> +	if ((to + len) > mtd->size)
> +		return -EINVAL;
> +	if (!len)
> +		return 0;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	ops.len = len;
> +	ops.datbuf = (uint8_t *)buf;
> +
> +	ret =  spinand_write_ops(mtd, to, &ops);
> +
> +	*retlen = ops.retlen;
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_read_oob(struct mtd_info *mtd, loff_t from,
> +			  struct mtd_oob_ops *ops)
> +{
> +	int ret;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	ret = spinand_read_ops(mtd, from, ops);
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +static int spinand_write_oob(struct mtd_info *mtd, loff_t to,
> +			  struct mtd_oob_ops *ops)
> +{
> +	int ret;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	ret = spinand_write_ops(mtd, to, ops);
> +	
> +	spinand_release_device(mtd);
> +	
> +	return ret;
> +}
> +
> +/**
> + * spinand_erase - [MTD Interface] erase block(s)
> + * @param mtd		MTD device structure
> + * @param instr		erase instruction
> + *
> + * Erase one ore more blocks
> + */
> +static int spinand_erase(struct mtd_info *mtd, struct erase_info
> *instr)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id, block_num, count;
> +	signed int retval=0;
> +	signed int errcode=0;
> +
> +	DEBUG(MTD_DEBUG_LEVEL3, "spinand_erase: start = 0x%012llx, len =
> %llu\n",
> +	      (unsigned long long)instr->addr, (unsigned long
> long)instr->len);
> +
> +	/* check address align on block boundary */
> +	if (instr->addr & (info->block_main_size - 1)) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: Unaligned
> address\n");
> +		return -EINVAL;
> +	}
> +
> +	if (instr->len & (info->block_main_size - 1)) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: "
> +		      "Length not block aligned\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Do not allow erase past end of device */
> +	if ((instr->len + instr->addr) > info->usable_size) {
> +		DEBUG(MTD_DEBUG_LEVEL0, "spinand_erase: "
> +		      "Erase past end of device\n");
> +		return -EINVAL;
> +	}
> +
> +	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;	
> +
> +	
> +	/* Grab the lock and see if the device is available */
> +	spinand_get_device(mtd, FL_ERASING);
> +
> +	block_id = instr->addr >> info->block_shift;
> +	block_num = instr->len >> info->block_shift; 
> +	count = 0;
> +	
> +	while (count < block_num )
> +	{
> +		retval = chip->erase_block(spi_nand, info,
> block_id+count);
> +
> +		if (retval!=0)
> +		{
> +			retval = chip->erase_block(spi_nand, info,
> block_id+count);
> +			if (retval!=0)
> +			{
> +				printk(KERN_INFO "spinand_erase: fail,
> block=%d!\n", block_id+count);
> +				errcode = -1;
> +			}
> +		}
> +		count++;
> +	}
> +	
> +	if (errcode == 0)
> +	{
> +		instr->state = MTD_ERASE_DONE;
> +	}
> +	
> +	/* Deselect and wake up anyone waiting on the device */
> +	spinand_release_device(mtd);
> +
> +	/* Do call back function */
> +	if(instr->callback)
> +		instr->callback(instr);
> +	
> +	return errcode;
> +}
> +
> +/**
> + * spinand_sync - [MTD Interface] sync
> + * @param mtd		MTD device structure
> + *
> + * Sync is actually a wait for chip ready function
> + */
> +static void spinand_sync(struct mtd_info *mtd)
> +{
> +	DEBUG(MTD_DEBUG_LEVEL3, "spinand_sync: called\n");
> +
> +	/* Grab the lock and see if the device is available */
> +	spinand_get_device(mtd, FL_SYNCING);
> +
> +	/* Release it and go back */
> +	spinand_release_device(mtd);
> +}
> +
> +static int spinand_block_isbad(struct mtd_info *mtd, loff_t ofs)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id;
> +	u8 is_bad = 0x00;
> +	u8 ret = 0;
> +
> +	spinand_get_device(mtd, FL_READING);
> +
> +	block_id = ofs >> info->block_shift;
> +
> +	chip->read_page(spi_nand, info,
> block_id*info->page_num_per_block, info->page_main_size, 1, &is_bad);
> +
> +	if (is_bad != 0xFF)
> +	{
> +		ret =  1;	
> +	}
> +
> +	spinand_release_device(mtd);
> +
> +	return ret; 
> +}
> +
> +/**
> + * spinand_block_markbad - [MTD Interface] Mark bad block
> + * @param mtd		MTD device structure
> + * @param ofs       Bad block number
> + */
> +static int spinand_block_markbad(struct mtd_info *mtd, loff_t ofs)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spi_device *spi_nand = chip->spi_nand;
> +	struct spinand_info *info = chip->info;
> +	u16 block_id;
> +	u8 is_bad = 0x00; 
> +	u8 ret = 0;
> +
> +	spinand_get_device(mtd, FL_WRITING);
> +
> +	block_id = ofs >> info->block_shift;
> +
> +	chip->program_page(spi_nand, info,
> block_id*info->page_num_per_block, info->page_main_size, 1, &is_bad);
> +
> +	spinand_release_device(mtd);
> +
> +	return ret;
> +}
> +
> +
> +/**
> + * spinand_suspend - [MTD Interface] Suspend the spinand flash
> + * @param mtd		MTD device structure
> + */
> +static int spinand_suspend(struct mtd_info *mtd)
> +{
> +	return spinand_get_device(mtd, FL_PM_SUSPENDED);
> +}
> +
> +/**
> + * spinand_resume - [MTD Interface] Resume the spinand flash
> + * @param mtd		MTD device structure
> + */
> +static void spinand_resume(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *this = mtd->priv;
> +
> +	if (this->state == FL_PM_SUSPENDED)
> +		spinand_release_device(mtd);
> +	else
> +		printk(KERN_ERR "resume() called for the chip which is
> not"
> +				"in suspended state\n");
> +}
> +
> +/**
> + * spinand_mtd - add MTD device with parameters
> + * @param mtd		MTD device structure
> + *
> + * Add MTD device with parameters.
> + */
> +int spinand_mtd(struct mtd_info *mtd)
> +{
> +	struct spinand_chip *chip = mtd->priv;
> +	struct spinand_info *info = chip->info;
> +
> +	chip->state = FL_READY;
> +	init_waitqueue_head(&chip->wq);
> +	spin_lock_init(&chip->chip_lock);
> +
> +	mtd->name = info->name;
> +	mtd->size = info->usable_size;
> +	mtd->erasesize = info->block_main_size;
> +	mtd->writesize = info->page_main_size;
> +	mtd->oobsize = info->ecclayout->oobavail;
> +	mtd->owner = THIS_MODULE;
> +	mtd->type = MTD_NANDFLASH;
> +	mtd->flags = MTD_CAP_NANDFLASH;
> +
> +	mtd->ecclayout = info->ecclayout;
> +
> +	mtd->erase = spinand_erase;
> +	mtd->point = NULL;
> +	mtd->unpoint = NULL;
> +	mtd->read = spinand_read;
> +	mtd->write = spinand_write;
> +	mtd->read_oob = spinand_read_oob;
> +	mtd->write_oob = spinand_write_oob;
> +	mtd->sync = spinand_sync;
> +	mtd->lock = NULL;
> +	mtd->unlock = NULL;
> +	mtd->suspend = spinand_suspend;
> +	mtd->resume = spinand_resume;
> +	mtd->block_isbad = spinand_block_isbad;
> +	mtd->block_markbad = spinand_block_markbad;
> +	
> +	return add_mtd_device(mtd) == 1 ? -ENODEV : 0;
> +}
> +
> +void spinand_mtd_release(struct mtd_info *mtd)
> +{
> +	del_mtd_device(mtd);
> +}
> +
> +EXPORT_SYMBOL_GPL(spinand_mtd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Henry Pan <hspan at micron.com>");
> +MODULE_DESCRIPTION("SPI NAND driver code");
> diff -urN linux-2.6.33.20-orig/include/linux/mtd/spinand.h
> linux-2.6.33.20/include/linux/mtd/spinand.h
> --- linux-2.6.33.20-orig/include/linux/mtd/spinand.h	1969-12-31
> 16:00:00.000000000 -0800
> +++ linux-2.6.33.20/include/linux/mtd/spinand.h	2010-05-19
> 04:28:07.000000000 -0700
> @@ -0,0 +1,160 @@
> +/*
> + *  linux/include/linux/mtd/spinand.h
> + *
> + Copyright (c) 2009-2010 Micron Technology, Inc.
> +
> +This software is licensed under the terms of the GNU General Public
> +License version 2, as published by the Free Software Foundation, and
> +may be copied, distributed, and modified under those terms.
> +
> +This program is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> + *  Henry Pan <hspan at micron.com>
> + *
> + *  based on nand.h
> + */
> +#ifndef __LINUX_MTD_SPI_NAND_H
> +#define __LINUX_MTD_SPI_NAND_H
> +
> +#include <linux/wait.h>
> +#include <linux/spinlock.h>
> +#include <linux/mtd/mtd.h>
> +
> +/* cmd */
> +#define CMD_READ				0x13
> +#define CMD_READ_RDM			0x03
> +#define CMD_PROG_PAGE_CLRCACHE	0x02
> +#define CMD_PROG_PAGE			0x84
> +#define CMD_PROG_PAGE_EXC		0x10
> +#define CMD_ERASE_BLK			0xd8
> +#define CMD_WR_ENABLE			0x06
> +#define CMD_WR_DISABLE			0x04
> +#define CMD_READ_ID			0x9f
> +#define CMD_RESET				0xff
> +#define CMD_READ_REG			0x0f
> +#define CMD_WRITE_REG			0x1f
> +
> +/* feature/ status reg */
> +#define REG_BLOCK_LOCK		0xa0
> +#define REG_OTP				0xb0
> +#define REG_STATUS			0xc0/* timing */
> +
> +/* status */
> +#define STATUS_OIP_MASK		0x01
> +#define STATUS_READY		0 << 0
> +#define STATUS_BUSY			1 << 0
> +
> +#define STATUS_E_FAIL_MASK	0x04
> +#define STATUS_E_FAIL		1 << 2
> +
> +#define STATUS_P_FAIL_MASK 	0x08
> +#define STATUS_P_FAIL		1 << 3
> +
> +#define STATUS_ECC_MASK 	0x30
> +#define STATUS_ECC_1BIT_CORRECTED	1 << 4
> +#define STATUS_ECC_ERROR			2 << 4
> +#define STATUS_ECC_RESERVED			3 << 4
> +
> +
> +/*ECC enable defines*/
> +#define OTP_ECC_MASK		0x10
> +#define OTP_ECC_OFF			0
> +#define OTP_ECC_ON			1
> +
> +#define ECC_DISABLED
> +#define ECC_IN_NAND   
> +#define ECC_SOFT
> +
> +/* block lock */
> +#define BL_ALL_LOCKED      0x38 
> +#define BL_1_2_LOCKED      0x30
> +#define BL_1_4_LOCKED      0x28
> +#define BL_1_8_LOCKED      0x20
> +#define BL_1_16_LOCKED     0x18
> +#define BL_1_32_LOCKED     0x10
> +#define BL_1_64_LOCKED     0x08
> +#define BL_ALL_UNLOCKED    0
> +
> +/**********************************************************************
> ******/
> +
> +struct spinand_info {
> +	u8		mid;
> +	u8		did;
> +	char		*name;
> +	u64		nand_size;
> +	u64		usable_size;
> +
> +	u32		block_size;
> +	u32		block_main_size;
> +	/*u32		block_spare_size; */
> +	u16		block_num_per_chip;
> +	
> +	u16		page_size;
> +	u16		page_main_size;
> +	u16		page_spare_size;
> +	u16		page_num_per_block;
> +	
> +	u8		block_shift;
> +	u32		block_mask;
> +
> +	u8		page_shift;
> +	u16		page_mask;
> +
> +	struct nand_ecclayout *ecclayout;
> +};
> +
> +typedef enum {
> +	FL_READY,
> +	FL_READING,
> +	FL_WRITING,
> +	FL_ERASING,
> +	FL_SYNCING,
> +	FL_LOCKING,
> +	FL_RESETING,
> +	FL_OTPING,
> +	FL_PM_SUSPENDED,
> +} spinand_state_t;
> +	
> +struct spinand_chip { /* used for multi chip */
> +	spinlock_t		chip_lock;
> +	wait_queue_head_t wq;	
> +	spinand_state_t	state;
> +	struct spi_device	*spi_nand;
> +	struct spinand_info *info;
> +	/*struct mtd_info	*mtd; */
> +
> +	int (*reset) (struct spi_device *spi_nand);
> +	int (*read_id) (struct spi_device *spi_nand, u8* id);
> +	int (*read_page) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* rbuf);
> +	int (*program_page) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 page_id, u16 offset, u16 len, u8* wbuf);
> +	int (*erase_block) (struct spi_device *spi_nand, struct
> spinand_info *info, u16 block_id);
> +
> +	u8 *buf;
> +	u8 *oobbuf; /* temp buffer */
> +
> +
> +#ifdef CONFIG_MTD_SPINAND_SWECC
> +	u8 ecc_calc[12];
> +	u8 ecc_code[12];
> +#endif
> +};
> +
> +struct spinand_cmd {
> +	u8 cmd;
> +	unsigned n_addr;	
> +	u8 addr[3];
> +	unsigned n_dummy;
> +	unsigned n_tx;	
> +	u8 *tx_buf;
> +	unsigned n_rx;
> +	u8 *rx_buf;
> +};
> +
> +extern int spinand_mtd(struct mtd_info *mtd);
> +extern void spinand_mtd_release(struct mtd_info *mtd);
> +
> +
> +#endif /* __LINUX_MTD_SPI_NAND_H */

Thanks,
Kamlakant Patel



From dmosberger at gmail.com  Wed Jun 19 17:40:45 2013
From: dmosberger at gmail.com (David Mosberger-Tang)
Date: Wed, 19 Jun 2013 15:40:45 -0600
Subject: [Q] Using Micron 4-bit on-die ECC with v2.6.36 kernel?
In-Reply-To: <17588192.75Agdljyqk@laclwks004>
References: <17588192.75Agdljyqk@laclwks004>
Message-ID: <CACwUX0O37px3-cDAScXaFdQPahtnTayN0HKD_dz7U6dD69EURw@mail.gmail.com>

[Resend as plain text...]

Attached is a patch relative to 2.6.27.y.   We use it with a 16-bit
wide Micron part needing 4-bit ECC.  It works for us, YMMV.  I'm
pretty sure the raw access is broken badly but we are not using that
so it's not a problem from us.  The patch assumes that on-die ECC is
enabled in the bootstrap loader.

On Wed, Jun 19, 2013 at 8:14 AM, Brian Foster
<brian.foster at maximintegrated.com> wrote:
>
>  Our current reference Linux kernel for the MAX32590 (JIBE)
>  is based on v2.6.36.  (Unfortunately, upgrading to a more
>  recent version is not within the timeframe for solving the
>  current problem.)  Our recent reference boards use one of
>  those Micron NAND chips with an on-die 4-bit ECC, which we
>  have basically ignored:  To-date, we have simply used the
>  usual 1-bit ECC (i.e., living dangerously!).
>
>  This must change, and indeed we now have a case on my desk
>  where, had we been using the on-die ECC, it would have saved
>  us a ton of grief.  The problem is our kernel version is far
>  too old to take advantage of any of the recent-ish work for
>  on-die ECC.
>
>  Hence, I am looking into the possibility of adding on-die ECC
>  support to our JIBE controller driver specifically for such
>  NAND chips (or at least the specific Micron NAND chip on the
>  reference boards).  Broadly, pretending JIBE's H/W directly
>  supports on-die ECC, but actually doing the work in the driver.
>  A similar trick we played in the past (bitwise-inverted ECC
>  (now obsoleted and long-removed from the driver)) suggests
>  this is not too difficult.
>
>  I am looking for hints (suggestions), gotchas (warnings),
>  and/or any examples of similar (or other plausible) approaches.
>  Or for something I am overlooking in (or available for) kernels
>  of approximately the vintage we are using.
>
> Thanks & cheers!
>         -blf-
>
> p.s.  At the present time, I am not too interested in the
>      problem of converting existing boards.  This MAY change
>      as the scope and details of the solution become more
>      apparent.
>
> --
> Brian Foster
> Principal MTS, Software        |  La Ciotat, France
> Maxim Integrated               |  http://www.maximintegrated.com/
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
-------------- next part --------------
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 3387e0d..9d352f3 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -255,7 +255,7 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
  * buf:        buffer to store read data
  */
 static int atmel_nand_read_page(struct mtd_info *mtd,
-		struct nand_chip *chip, uint8_t *buf)
+				struct nand_chip *chip, uint8_t *buf, int page)
 {
 	int eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d1129ba..b7abe82 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -82,6 +82,20 @@ static struct nand_ecclayout nand_oob_64 = {
 		 .length = 38}}
 };
 
+static struct nand_ecclayout nand_oob_64_on_die = {
+	.eccbytes = 32,
+	.eccpos = {
+		    8,  9, 10, 11, 12, 13, 14, 15,
+		   24, 25, 26, 27, 28, 29, 30, 31,
+		   40, 41, 42, 43, 44, 45, 46, 47,
+		   56, 57, 58, 59, 60, 61, 62, 63},
+	.oobfree = {
+		{.offset =  4,	 .length = 4},
+		{.offset = 20,	 .length = 4},
+		{.offset = 36,	 .length = 4},
+		{.offset = 52,	 .length = 4}}
+};
+
 static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
 			   int new_state);
 
@@ -434,6 +448,32 @@ void nand_wait_ready(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(nand_wait_ready);
 
+static int
+set_column (struct mtd_info *mtd, struct nand_chip *chip,
+	    unsigned int command, int column,
+	    unsigned int column_width, int ctrl)
+{
+	switch (command) {
+	case NAND_CMD_READID:
+	case NAND_CMD_GET_FEATURES:
+	case NAND_CMD_SET_FEATURES:
+		chip->cmd_ctrl(mtd, column, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+		break;
+
+	default:
+		/* Adjust columns for 16 bit buswidth */
+		if (chip->options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		chip->cmd_ctrl(mtd, column, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+		if (column_width > 8)
+			chip->cmd_ctrl(mtd, column >> 8, ctrl);
+		break;
+	}
+	return ctrl;
+}
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd:	MTD device structure
@@ -477,13 +517,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
 	 */
 	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
 	/* Serially input address */
-	if (column != -1) {
-		/* Adjust columns for 16 bit buswidth */
-		if (chip->options & NAND_BUSWIDTH_16)
-			column >>= 1;
-		chip->cmd_ctrl(mtd, column, ctrl);
-		ctrl &= ~NAND_CTRL_CHANGE;
-	}
+	if (column != -1)
+		ctrl = set_column(mtd, chip, command, column, 8, ctrl);
 	if (page_addr != -1) {
 		chip->cmd_ctrl(mtd, page_addr, ctrl);
 		ctrl &= ~NAND_CTRL_CHANGE;
@@ -566,14 +601,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
 
 		/* Serially input address */
-		if (column != -1) {
-			/* Adjust columns for 16 bit buswidth */
-			if (chip->options & NAND_BUSWIDTH_16)
-				column >>= 1;
-			chip->cmd_ctrl(mtd, column, ctrl);
-			ctrl &= ~NAND_CTRL_CHANGE;
-			chip->cmd_ctrl(mtd, column >> 8, ctrl);
-		}
+		if (column != -1)
+			ctrl = set_column (mtd, chip, command, column, 16,
+					   ctrl);
 		if (page_addr != -1) {
 			chip->cmd_ctrl(mtd, page_addr, ctrl);
 			chip->cmd_ctrl(mtd, page_addr >> 8,
@@ -750,7 +780,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
  * @buf:	buffer to store read data
  */
 static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-			      uint8_t *buf)
+			      uint8_t *buf, int page)
 {
 	chip->read_buf(mtd, buf, mtd->writesize);
 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -764,7 +794,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  * @buf:	buffer to store read data
  */
 static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf)
+				uint8_t *buf, int page)
 {
 	int i, eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
@@ -774,7 +804,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 	uint8_t *ecc_code = chip->buffers->ecccode;
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
-	chip->ecc.read_page_raw(mtd, chip, buf);
+	chip->ecc.read_page_raw(mtd, chip, buf, page);
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -805,7 +835,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @readlen	data length
  * @buf:	buffer to store read data
  */
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
 {
 	int start_step, end_step, num_steps;
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -887,7 +917,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
  * Not for syndrome calculating ecc controllers which need a special oob layout
  */
 static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf)
+				uint8_t *buf, int page)
 {
 	int i, eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
@@ -932,7 +962,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * we need a special oob layout and handling.
  */
 static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-				   uint8_t *buf)
+				   uint8_t *buf, int page)
 {
 	int i, eccsize = chip->ecc.size;
 	int eccbytes = chip->ecc.bytes;
@@ -1025,6 +1055,80 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
 }
 
 /**
+ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+			int addr, uint8_t *subfeature_param)
+{
+	uint16_t buf[ONFI_SUBFEATURE_PARAM_LEN];
+	size_t len = ONFI_SUBFEATURE_PARAM_LEN;
+	int status, i;
+
+	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
+	if (chip->options & NAND_BUSWIDTH_16) {
+		/*
+		 * ONFI says parameters are always transferred on the
+		 * lower 8-bits of the databus.  Since there is no
+		 * chip->write_byte callback, we have to convert
+		 * subfeature_param to 16-bit data.
+		 */
+		for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+			buf[i] = subfeature_param[i];
+		subfeature_param = (uint8_t *) buf;
+		len = sizeof (buf);
+	}
+	chip->write_buf(mtd, subfeature_param, len);
+	status = chip->waitfunc(mtd, chip);
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+	return 0;
+}
+
+/**
+ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+			int addr, uint8_t *subfeature_param)
+{
+	int i;
+
+	/* clear the sub feature parameters */
+	memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
+
+	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
+	/*
+	 * ONFI says parameters are always transferred on the
+	 * lower 8-bits of the databus.  Use read_byte() since
+	 * that works even on 16-bit devices.
+	 */
+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+	  subfeature_param[i] = chip->read_byte(mtd);
+	return 0;
+}
+
+static int
+set_on_die_ecc (struct mtd_info *mtd, struct nand_chip *chip, int on)
+{
+	u8 data[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+
+	if (chip->ecc.mode != NAND_ECC_HW_ON_DIE)
+		return 0;
+
+	if (on)
+		data[0] = 0x8;
+
+	return nand_onfi_set_features(mtd, chip, 0x90, data);
+}
+
+/**
  * nand_do_read_ops - [Internal] Read data with ECC
  *
  * @mtd:	MTD device structure
@@ -1068,17 +1172,20 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 			bufpoi = aligned ? buf : chip->buffers->databuf;
 
 			if (likely(sndcmd)) {
+				if (unlikely(ops->mode == MTD_OOB_RAW))
+					set_on_die_ecc(mtd, chip, 0);
+
 				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 				sndcmd = 0;
 			}
 
 			/* Now read the page into the buffer */
 			if (unlikely(ops->mode == MTD_OOB_RAW))
-				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
+				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page);
 			else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
-				ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
+				ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi, page);
 			else
-				ret = chip->ecc.read_page(mtd, chip, bufpoi);
+				ret = chip->ecc.read_page(mtd, chip, bufpoi, page);
 			if (ret < 0)
 				break;
 
@@ -1149,6 +1256,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 			sndcmd = 1;
 	}
 
+	set_on_die_ecc(mtd, chip, 1);
+
 	ops->retlen = ops->len - (size_t) readlen;
 	if (oob)
 		ops->oobretlen = ops->ooblen - oobreadlen;
@@ -1162,6 +1271,173 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
+/*
+ * Return the number of bits that differ between buffers SRC1 and
+ * SRC2, both of which are LEN bytes long.
+ *
+ * This code could be optimized for, but it only gets called on pages
+ * with bitflips and compared to the cost of migrating an eraseblock,
+ * the execution time here is trivial...
+ */
+static int
+bitdiff (const void *s1, const void *s2, size_t len)
+{
+	const uint8_t *src1 = s1, *src2 = s2;
+	int count = 0, i;
+
+	for (i = 0; i < len; ++i)
+		count += hweight8 (*src1++ ^ *src2++);
+	return count;
+}
+
+static int
+check_for_bitflips (struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	int flips = 0, max_bitflips = 0, i, j, read_size;
+	uint8_t *chkbuf, *rawbuf, *chkoob, *rawoob;
+	uint32_t *eccpos;
+
+	chkbuf = chip->buffers->chkbuf;
+	rawbuf = chip->buffers->rawbuf;
+	read_size = mtd->writesize + mtd->oobsize;
+
+	/* Read entire page w/OOB area with on-die ECC on: */
+	chip->read_buf(mtd, chkbuf, read_size);
+
+	/* Re-read page with on-die ECC off: */
+	set_on_die_ecc(mtd, chip, 0);
+	{
+		chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+		chip->read_buf(mtd, rawbuf, read_size);
+	}
+	set_on_die_ecc(mtd, chip, 1);
+
+	chkoob = chkbuf + mtd->writesize;
+	rawoob = rawbuf + mtd->writesize;
+	eccpos = chip->ecc.layout->eccpos;
+	for (i = 0; i < chip->ecc.steps; ++i) {
+		/* Count bit flips in the actual data area: */
+		flips = bitdiff (chkbuf, rawbuf, chip->ecc.size);
+		/* Count bit flips in the ECC bytes: */
+		for (j = 0; j < chip->ecc.bytes; ++j) {
+			flips += hweight8(chkoob[*eccpos] ^ rawoob[*eccpos]);
+			++eccpos;
+		}
+		max_bitflips = max_t(int, max_bitflips, flips);
+		if (max_bitflips >= 3)
+			mtd->ecc_stats.corrected++;
+		chkbuf += chip->ecc.size;
+		rawbuf += chip->ecc.size;
+	}
+
+	/* Re-issue the READ command for the actual data read that follows.  */
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+
+	return max_bitflips;
+}
+
+static int check_read_status_on_die (struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	uint8_t status;
+
+	/* Check ECC status of page just transferred into NAND's page buffer: */
+	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+	status = chip->read_byte(mtd);
+
+	/* Switch back to data reading: */
+	chip->cmd_ctrl(mtd, NAND_CMD_READ0,
+		       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+	chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+		       NAND_NCE | NAND_CTRL_CHANGE);
+
+	if (status & NAND_STATUS_FAIL) {
+		/* Page has invalid ECC. */
+		mtd->ecc_stats.failed++;
+	} else if (status & NAND_STATUS_REWRITE) {
+		/*
+		 * The Micron chips turn on the REWRITE status bit for
+		 * ANY bit flips.  Some pages have stuck bits, so we
+		 * don't want to migrate a block just because of
+		 * single bit errors because otherwise, that block
+		 * would effectively become unusable.  So, work out in
+		 * software what the max number of flipped bits is for
+		 * all subpages in a page:
+		 */
+		check_for_bitflips (mtd, chip, page);
+	}
+	return 0;
+}
+
+/**
+ * nand_read_subpage_on_die - [REPLACEABLE] raw sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
+ */
+static int nand_read_subpage_on_die(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
+{
+	int start_step, end_step, num_steps, ret;
+	int data_col_addr;
+	int datafrag_len;
+	uint32_t failed;
+	uint8_t *p;
+
+	/* Column address within the page aligned to ECC size */
+	start_step = data_offs / chip->ecc.size;
+	end_step = (data_offs + readlen - 1) / chip->ecc.size;
+	num_steps = end_step - start_step + 1;
+
+	/* Data size aligned to ECC ecc.size */
+	datafrag_len = num_steps * chip->ecc.size;
+	data_col_addr = start_step * chip->ecc.size;
+	p = bufpoi + data_col_addr;
+
+	failed = mtd->ecc_stats.failed;
+
+	ret = check_read_status_on_die (mtd, chip, page);
+	if (ret < 0 || mtd->ecc_stats.failed != failed) {
+		memset (p, 0, datafrag_len);
+		return ret;
+	}
+
+	/* If we read not a page aligned data */
+	if (data_col_addr != 0)
+		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
+
+	chip->read_buf(mtd, p, datafrag_len);
+
+	return ret;
+}
+
+/**
+ * nand_read_page_on_die - [INTERN] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ */
+static int nand_read_page_on_die(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf,
+				 int page)
+{
+	uint32_t failed;
+	int ret;
+
+	failed = mtd->ecc_stats.failed;
+
+	ret = check_read_status_on_die (mtd, chip, page);
+	if (ret < 0 || mtd->ecc_stats.failed != failed) {
+		memset (buf, 0, mtd->writesize);
+		return ret;
+	}
+
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return ret;
+}
+
 /**
  * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:	MTD device structure
@@ -1602,6 +1878,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 {
 	int status;
 
+	if (unlikely(raw))
+		set_on_die_ecc(mtd, chip, 0);
+
 	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
 	if (unlikely(raw))
@@ -1627,11 +1906,16 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 			status = chip->errstat(mtd, chip, FL_WRITING, status,
 					       page);
 
+		if (unlikely(raw))
+			set_on_die_ecc(mtd, chip, 1);
+
 		if (status & NAND_STATUS_FAIL)
 			return -EIO;
 	} else {
 		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
 		status = chip->waitfunc(mtd, chip);
+		if (unlikely(raw))
+			set_on_die_ecc(mtd, chip, 1);
 	}
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
@@ -2518,6 +2802,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
 int nand_scan_tail(struct mtd_info *mtd)
 {
 	int i;
+	u8 features[ONFI_SUBFEATURE_PARAM_LEN];
 	struct nand_chip *chip = mtd->priv;
 
 	if (!(chip->options & NAND_OWN_BUFFERS))
@@ -2552,6 +2837,16 @@ int nand_scan_tail(struct mtd_info *mtd)
 	if (!chip->write_page)
 		chip->write_page = nand_write_page;
 
+	if (nand_onfi_get_features(mtd, chip, 0x90, features) >= 0) {
+		if (features[0] & 0x08) {
+			/*
+			 * If the chip has on-die ECC enabled, we kind of have to use it.
+			 */
+			chip->ecc.mode = NAND_ECC_HW_ON_DIE;
+			pr_info("NAND device: Using on-die ECC\n");
+		}
+	}
+
 	/*
 	 * check ECC mode, default to software if 3byte/512byte hardware ECC is
 	 * selected and we have 256 byte pagesize fallback to software ECC
@@ -2613,6 +2908,19 @@ int nand_scan_tail(struct mtd_info *mtd)
 		chip->ecc.bytes = 3;
 		break;
 
+	case NAND_ECC_HW_ON_DIE:
+		chip->ecc.layout = &nand_oob_64_on_die;
+		chip->ecc.read_page = nand_read_page_on_die;
+		chip->ecc.read_subpage = nand_read_subpage_on_die;
+		chip->ecc.write_page = nand_write_page_raw;
+		chip->ecc.read_oob = nand_read_oob_std;
+		chip->ecc.read_page_raw = nand_read_page_raw;
+		chip->ecc.write_page_raw = nand_write_page_raw;
+		chip->ecc.write_oob = nand_write_oob_std;
+		chip->ecc.size = 512;
+		chip->ecc.bytes = 8;
+		break;
+
 	case NAND_ECC_NONE:
 		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
 		       "This is not recommended !!\n");
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 0b1c485..f09e80c 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1117,7 +1117,9 @@ static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
 static struct nand_bbt_descr bbt_main_descr = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
+	/* Micron MT29F4G16ABADAWP places ECC at offset 8, so we use 4
+	   instead (User metadata I).  */
+	.offs =	4,
 	.len = 4,
 	.veroffs = 12,
 	.maxblocks = 4,
@@ -1127,7 +1129,9 @@ static struct nand_bbt_descr bbt_main_descr = {
 static struct nand_bbt_descr bbt_mirror_descr = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
+	/* Micron MT29F4G16ABADAWP places ECC at offset 8, so we use 4
+	   instead (User metadata I).  */
+	.offs =	4,
 	.len = 4,
 	.veroffs = 12,
 	.maxblocks = 4,
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 81774e5..cbdb01e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -78,6 +78,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_CMD_RNDIN		0x85
 #define NAND_CMD_READID		0x90
 #define NAND_CMD_ERASE2		0xd0
+#define NAND_CMD_GET_FEATURES	0xee
+#define NAND_CMD_SET_FEATURES	0xef
 #define NAND_CMD_RESET		0xff
 
 /* Extended commands for large page devices */
@@ -109,6 +111,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
 /* Status bits */
 #define NAND_STATUS_FAIL	0x01
 #define NAND_STATUS_FAIL_N1	0x02
+#define NAND_STATUS_REWRITE	0x08
 #define NAND_STATUS_TRUE_READY	0x20
 #define NAND_STATUS_READY	0x40
 #define NAND_STATUS_WP		0x80
@@ -121,6 +124,7 @@ typedef enum {
 	NAND_ECC_SOFT,
 	NAND_ECC_HW,
 	NAND_ECC_HW_SYNDROME,
+	NAND_ECC_HW_ON_DIE,
 } nand_ecc_modes_t;
 
 /*
@@ -178,8 +182,9 @@ typedef enum {
 #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
 /* Large page NAND with SOFT_ECC should support subpage reads */
-#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
-					&& (chip->page_shift > 9))
+#define NAND_SUBPAGE_READ(chip)	(((chip->ecc.mode == NAND_ECC_SOFT) ||	\
+				  (chip->ecc.mode == NAND_ECC_HW_ON_DIE)) \
+				 && (chip->page_shift > 9))
 
 /* Mask to zero out the chip options, which come from the id table */
 #define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)
@@ -270,17 +275,17 @@ struct nand_ecc_ctrl {
 					   uint8_t *calc_ecc);
 	int			(*read_page_raw)(struct mtd_info *mtd,
 						 struct nand_chip *chip,
-						 uint8_t *buf);
+						 uint8_t *buf, int page);
 	void			(*write_page_raw)(struct mtd_info *mtd,
 						  struct nand_chip *chip,
 						  const uint8_t *buf);
 	int			(*read_page)(struct mtd_info *mtd,
 					     struct nand_chip *chip,
-					     uint8_t *buf);
+					     uint8_t *buf, int page);
 	int			(*read_subpage)(struct mtd_info *mtd,
 					     struct nand_chip *chip,
 					     uint32_t offs, uint32_t len,
-					     uint8_t *buf);
+						uint8_t *buf, int page);
 	void			(*write_page)(struct mtd_info *mtd,
 					      struct nand_chip *chip,
 					      const uint8_t *buf);
@@ -306,6 +311,8 @@ struct nand_buffers {
 	uint8_t	ecccalc[NAND_MAX_OOBSIZE];
 	uint8_t	ecccode[NAND_MAX_OOBSIZE];
 	uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+	uint8_t chkbuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+	uint8_t rawbuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
 };
 
 /**
@@ -611,6 +618,9 @@ struct platform_nand_data {
 	struct platform_nand_ctrl	ctrl;
 };
 
+/* ONFI subfeature parameters length */
+#define ONFI_SUBFEATURE_PARAM_LEN	4
+
 /* Some helpers to access the data structures */
 static inline
 struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)

From Adeange1 at villanova.edu  Thu Jun 20 01:06:36 2013
From: Adeange1 at villanova.edu (Alec Duncan)
Date: Thu, 20 Jun 2013 10:36:36 +0530
Subject: Bequest Donation of $10 Million
Message-ID: <6ba96811-76cb-4174-a592-6a83259747f2@VUEX14HUB1.vuad.villanova.edu>

I have will my estate to you for the work of humanity, for more information contact Attorney Newton Blackwell on email: npowell at rogers.com


From Noel.Vellemans at visionBMS.com  Thu Jun 20 02:55:49 2013
From: Noel.Vellemans at visionBMS.com (Vellemans, Noel)
Date: Thu, 20 Jun 2013 08:55:49 +0200
Subject: CFC - RW - power-donw ?
Message-ID: <1531E53627F1F749B4FE809BF2A4EB67043D97FA@wetmex10>

Hi all,

I've a question regarding a PC that needs to boot from CFC (Compact
Flash card), hope this is the correct place to ask.

I would need a PC to boot from a CFC-card that has R/W enabled.

At this time I have been testing it with EXT2/EXT3 but when POWERING
down abruptly it seems that the CFC-ext2/ext3 file system gets
corrupted, finally resulting in a NON bootable system.

At this time I have partitioned the CFC into 2 partitions 1-FAT16 (to
store the kernel) and 1-ext2/ext3 partition that has the root-file
system.

What would be the correct file-system (and/or mount /build options) to
put on a CFC ... so that it is able to survive abrupt-power downs ?

Or is the somewhere a guide (URL) that explains me some more stuff
regarding this.

Thanks and Regards,
Noel








From Mats.Karrman at tritech.se  Thu Jun 20 08:14:40 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 20 Jun 2013 12:14:40 +0000
Subject: UBIFS: integck and tst_recovery
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FC93588@post.tritech.se>

Hi,

I want to use the integck program from mtd-utils for power-cut emulation
testing and I wonder how/if it is interrelated to to the debugfs
tst_recovery file.

I tried running integck with -p for a long time but got no errors.

I then enabled the tst_recovery (echo 1 > ....) and started the test
again. I immediately got a whole bunch of errors but as soon as the file
system was remounted the errors stopped. Checking tst_recovery I found
it was now disabled. Without stopping integck I then reenabled
tst_recovery and the same thing happened again.

If anyone could shed some light on how this is supposed to be used, I
would be glad!

I'm running the test on a separate "unused" UBIFS partition on a NOR
flash. The kernel version is 2.6.35 with all relevant UBIFS patches
from Linux stable.

BR // Mats

From mpfj-list at newflow.co.uk  Thu Jun 20 08:57:58 2013
From: mpfj-list at newflow.co.uk (Mark Jackson)
Date: Thu, 20 Jun 2013 13:57:58 +0100
Subject: 3.10.0-rc4: jffs2: Possible circular locking dependency detected
Message-ID: <51C2FC56.1070808@newflow.co.uk>

Just mounted a JFFS2 partition (held in NOR flash on a custom AM335x
CPU board), and I always get the following:-

[    3.864244]
[    3.865851] ======================================================
[    3.872359] [ INFO: possible circular locking dependency detected ]
[    3.878968] 3.10.0-rc4-00172-gf31c62e-dirty #249 Not tainted
[    3.884926] -------------------------------------------------------
[    3.891526] rcS/507 is trying to acquire lock:
[    3.896206]  (&mm->mmap_sem){++++++}, at: [<c00b42c8>] might_fault+0x3c/0x94
[    3.903684]
[    3.903684] but task is already holding lock:
[    3.909826]  (&f->sem){+.+.+.}, at: [<c016f208>] jffs2_readdir+0x40/0x1b0
[    3.917021]
[    3.917021] which lock already depends on the new lock.
[    3.917021]
[    3.925637]
[    3.925637] the existing dependency chain (in reverse order) is:
[    3.933516]
-> #1 (&f->sem){+.+.+.}:
[    3.937489]        [<c0079ad0>] lock_acquire+0x68/0x7c
[    3.942918]        [<c041f290>] mutex_lock_nested+0x40/0x31c
[    3.948893]        [<c0170b00>] jffs2_readpage+0x20/0x4c
[    3.954500]        [<c009faf4>] __do_page_cache_readahead+0x28c/0x2b4
[    3.961305]        [<c00a0028>] ra_submit+0x28/0x30
[    3.966450]        [<c009686c>] filemap_fault+0x330/0x3e4
[    3.972143]        [<c00b0308>] __do_fault+0x68/0x4a4
[    3.977481]        [<c00b3214>] handle_pte_fault+0x70/0x6b4
[    3.983361]        [<c00b38f0>] handle_mm_fault+0x98/0xcc
[    3.989055]        [<c001d614>] do_page_fault+0x210/0x398
[    3.994750]        [<c00084a4>] do_DataAbort+0x38/0x98
[    4.000170]        [<c001315c>] __dabt_svc+0x3c/0x60
[    4.005417]        [<c01df448>] __clear_user_std+0x1c/0x64
[    4.011209]
-> #0 (&mm->mmap_sem){++++++}:
[    4.015729]        [<c0078f40>] __lock_acquire+0x1990/0x1d7c
[    4.021699]        [<c0079ad0>] lock_acquire+0x68/0x7c
[    4.027118]        [<c00b42f0>] might_fault+0x64/0x94
[    4.032444]        [<c00d9bd0>] filldir+0x6c/0x174
[    4.037507]        [<c016f28c>] jffs2_readdir+0xc4/0x1b0
[    4.043110]        [<c00da020>] vfs_readdir+0x94/0xb8
[    4.048438]        [<c00da118>] SyS_getdents+0x64/0xd4
[    4.053859]        [<c00135c0>] ret_fast_syscall+0x0/0x48
[    4.059556]
[    4.059556] other info that might help us debug this:
[    4.059556]
[    4.067989]  Possible unsafe locking scenario:
[    4.067989]
[    4.074222]        CPU0                    CPU1
[    4.078989]        ----                    ----
[    4.083756]   lock(&f->sem);
[    4.086799]                                lock(&mm->mmap_sem);
[    4.093042]                                lock(&f->sem);
[    4.098735]   lock(&mm->mmap_sem);
[    4.102326]
[    4.102326]  *** DEADLOCK ***
[    4.102326]
[    4.108567] 2 locks held by rcS/507:
[    4.112328]  #0:  (&type->i_mutex_dir_key){+.+.+.}, at: [<c00d9fe0>] vfs_readdir+0x54/0xb8
[    4.121070]  #1:  (&f->sem){+.+.+.}, at: [<c016f208>] jffs2_readdir+0x40/0x1b0
[    4.128713]
[    4.128713] stack backtrace:
[    4.133312] CPU: 0 PID: 507 Comm: rcS Not tainted 3.10.0-rc4-00172-gf31c62e-dirty #249
[    4.141676] [<c0018e70>] (unwind_backtrace+0x0/0xf4) from [<c0016d88>] (show_stack+0x10/0x14)
[    4.150669] [<c0016d88>] (show_stack+0x10/0x14) from [<c041bc88>] (print_circular_bug+0x2e8/0x2f4)
[    4.160118] [<c041bc88>] (print_circular_bug+0x2e8/0x2f4) from [<c0078f40>] (__lock_acquire+0x1990/0x1d7c)
[    4.170297] [<c0078f40>] (__lock_acquire+0x1990/0x1d7c) from [<c0079ad0>] (lock_acquire+0x68/0x7c)
[    4.179742] [<c0079ad0>] (lock_acquire+0x68/0x7c) from [<c00b42f0>] (might_fault+0x64/0x94)
[    4.188549] [<c00b42f0>] (might_fault+0x64/0x94) from [<c00d9bd0>] (filldir+0x6c/0x174)
[    4.196992] [<c00d9bd0>] (filldir+0x6c/0x174) from [<c016f28c>] (jffs2_readdir+0xc4/0x1b0)
[    4.205708] [<c016f28c>] (jffs2_readdir+0xc4/0x1b0) from [<c00da020>] (vfs_readdir+0x94/0xb8)
[    4.214698] [<c00da020>] (vfs_readdir+0x94/0xb8) from [<c00da118>] (SyS_getdents+0x64/0xd4)
[    4.223507] [<c00da118>] (SyS_getdents+0x64/0xd4) from [<c00135c0>] (ret_fast_syscall+0x0/0x48)


From vincenzo.aliberti at gmail.com  Thu Jun 20 14:37:53 2013
From: vincenzo.aliberti at gmail.com (Vincenzo Aliberti)
Date: Thu, 20 Jun 2013 20:37:53 +0200
Subject: =?UTF-8?q?=5BPATCH=5D=20=5BMTD=5D=20MTD=20driver=20for=20LPDDR2-NVM=20PCM=20memories?=
Message-ID: <1371753473-2343-1-git-send-email-vincenzo.aliberti@gmail.com>

Added Support for PCM memories with LPDDR2-NVM interface

Signed-off-by: Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
---
 drivers/mtd/lpddr/Kconfig      |   12 +-
 drivers/mtd/lpddr/Makefile     |    1 +
 drivers/mtd/lpddr/lpddr2_nvm.c |  556 ++++++++++++++++++++++++++++++++++++++++
 include/uapi/mtd/mtd-abi.h     |    1 +
 4 files changed, 568 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mtd/lpddr/lpddr2_nvm.c

diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
index 265f969..468f06d 100644
--- a/drivers/mtd/lpddr/Kconfig
+++ b/drivers/mtd/lpddr/Kconfig
@@ -1,5 +1,5 @@
-menu "LPDDR flash memory drivers"
-	depends on MTD!=n
+menu "LPDDR & LPDDR2 PCM memory drivers"
+	depends on MTD
 
 config MTD_LPDDR
 	tristate "Support for LPDDR flash chips"
@@ -17,4 +17,12 @@ config MTD_QINFO_PROBE
 	    Window QINFO interface, permits software to be used for entire
 	    families of devices. This serves similar purpose of CFI on legacy
 	    Flash products
+
+config MTD_LPDDR2_NVM
+	depends on MTD
+	tristate "Support for LPDDR2-NVM flash chips"
+	help
+	  This option enables support of PCM memories with a LPDDR2-NVM
+	  (Low power double data rate 2) interface.
+
 endmenu
diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile
index da48e46..881d440 100644
--- a/drivers/mtd/lpddr/Makefile
+++ b/drivers/mtd/lpddr/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_MTD_QINFO_PROBE)	+= qinfo_probe.o
 obj-$(CONFIG_MTD_LPDDR)	+= lpddr_cmds.o
+obj-$(CONFIG_MTD_LPDDR2_NVM) += lpddr2_nvm.o
diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c
new file mode 100644
index 0000000..068f95d
--- /dev/null
+++ b/drivers/mtd/lpddr/lpddr2_nvm.c
@@ -0,0 +1,556 @@
+/*
+ * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock
+ * support for LPDDR2-NVM PCM memories
+ *
+ * Copyright ? 2012 Micron Technology, Inc.
+ *
+ * Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
+ * Domenico Manna <domenico.manna at gmail.com>
+ * Many thanks to Andrea Vigilante for initial enabling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+
+/* Parameters */
+#define ERASE_BLOCKSIZE			(0x00020000/2)	/* in Word */
+#define WRITE_BUFFSIZE			(0x00000400/2)	/* in Word */
+#define OW_BASE_ADDRESS			0x00000000	/* OW offset */
+
+/* PFOW symbols address offset */
+#define PFOW_QUERY_STRING_P		(0x0000/2)	/* in Word */
+#define PFOW_QUERY_STRING_F		(0x0002/2)	/* in Word */
+#define PFOW_QUERY_STRING_O		(0x0004/2)	/* in Word */
+#define PFOW_QUERY_STRING_W		(0x0006/2)	/* in Word */
+
+/* OW registers address */
+#define CMD_CODE_OFS			(0x0080/2)	/* in Word */
+#define CMD_DATA_OFS			(0x0084/2)	/* in Word */
+#define CMD_ADD_L_OFS			(0x0088/2)	/* in Word */
+#define CMD_ADD_H_OFS			(0x008A/2)	/* in Word */
+#define MPR_L_OFS			(0x0090/2)	/* in Word */
+#define MPR_H_OFS			(0x0092/2)	/* in Word */
+#define CMD_EXEC_OFS			(0x00C0/2)	/* in Word */
+#define STATUS_REG_OFS			(0x00CC/2)	/* in Word */
+#define PRG_BUFFER_OFS			(0x0010/2)	/* in Word */
+
+/* Datamask */
+#define MR_CFGMASK			0x8000
+#define SR_OK_DATAMASK			0x0080
+
+/* LPDDR2-NVM Commands */
+#define LPDDR2_NVM_LOCK			0x0061
+#define LPDDR2_NVM_UNLOCK		0x0062
+#define LPDDR2_NVM_SW_PROGRAM		0x0041
+#define LPDDR2_NVM_SW_OVERWRITE		0x0042
+#define LPDDR2_NVM_BUF_PROGRAM		0x00E9
+#define LPDDR2_NVM_BUF_OVERWRITE	0x00EA
+#define LPDDR2_NVM_ERASE		0x0020
+
+/*
+ * Internal Type Definitions
+ * pcm_int_data contains memory controller details:
+ * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
+ * @reg_cfg  : LPDDR2_MODE_REG_CFG register address after remapping
+ * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)
+ */
+struct pcm_int_data {
+	void __iomem *reg_data;
+	void __iomem *reg_cfg;
+	int bus_width;
+};
+
+static DEFINE_MUTEX(lpdd2_nvm_mutex);
+
+/*
+ * Build a map_word starting from an u_long
+ */
+static inline map_word build_map_word(u_long myword)
+{
+	map_word val = { {0} };
+	val.x[0] = myword;
+	return val;
+}
+
+/*
+ * Build Mode Register Configuration DataMask based on device bus-width
+ */
+static inline u_int build_mr_cfgmask(u_int bus_width)
+{
+	u_int val = MR_CFGMASK;
+
+	if (bus_width == 0x0004)		/* x32 device */
+		val = val<<16;
+
+	return val;
+}
+
+/*
+ * Build Status Register OK DataMask based on device bus-width
+ */
+static inline u_int build_sr_ok_datamask(u_int bus_width)
+{
+	u_int val = SR_OK_DATAMASK;
+
+	if (bus_width == 0x0004)		/* x32 device */
+		val = (val<<16)+val;
+
+	return val;
+}
+
+/*
+ * Evaluates Overlay Window Control Registers address
+ */
+static inline u_long ow_reg_add(struct map_info *map, u_long offset)
+{
+	u_long val = 0;
+	struct pcm_int_data *pcm_data = map->fldrv_priv;
+
+	val = map->pfow_base + offset*pcm_data->bus_width;
+
+	return val;
+}
+
+/*
+ * Enable lpddr2-nvm Overlay Window
+ * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
+ * used by device commands as well as uservisible resources like Device Status
+ * Register, Device ID, etc
+ */
+static inline void ow_enable(struct map_info *map)
+{
+	struct pcm_int_data *pcm_data = map->fldrv_priv;
+
+	writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
+		pcm_data->reg_cfg);
+	writel_relaxed(0x01, pcm_data->reg_data);
+}
+
+/*
+ * Disable lpddr2-nvm Overlay Window
+ * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
+ * used by device commands as well as uservisible resources like Device Status
+ * Register, Device ID, etc
+ */
+static inline void ow_disable(struct map_info *map)
+{
+	struct pcm_int_data *pcm_data = map->fldrv_priv;
+
+	writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
+		pcm_data->reg_cfg);
+	writel_relaxed(0x02, pcm_data->reg_data);
+}
+
+/*
+ * Execute lpddr2-nvm operations
+ */
+static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code,
+	u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf)
+{
+	map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} },
+		mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} },
+		exec_cmd = { {0} }, sr;
+	map_word data_h = { {0} };	/* only for 2x x16 devices stacked */
+	u_long i, status_reg, prg_buff_ofs;
+	struct pcm_int_data *pcm_data = map->fldrv_priv;
+	u_int sr_ok_datamask = build_sr_ok_datamask(pcm_data->bus_width);
+
+	/* Builds low and high words for OW Control Registers */
+	add_l.x[0]	= cmd_add&0x0000FFFF;
+	add_h.x[0]	= (cmd_add>>16)&0x0000FFFF;
+	mpr_l.x[0]	= cmd_mpr&0x0000FFFF;
+	mpr_h.x[0]	= (cmd_mpr>>16)&0x0000FFFF;
+	cmd.x[0]	= cmd_code&0x0000FFFF;
+	exec_cmd.x[0]	= 0x0001;
+	data_l.x[0]	= cmd_data&0x0000FFFF;
+	data_h.x[0]	= (cmd_data>>16)&0x0000FFFF; /* only for 2x x16 */
+
+	/* Set Overlay Window Control Registers */
+	map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS));
+	map_write(map, data_l, ow_reg_add(map, CMD_DATA_OFS));
+	map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS));
+	map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS));
+	map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS));
+	map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS));
+	if (pcm_data->bus_width == 0x0004) {	/* 2x16 devices stacked */
+		map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS) + 2);
+		map_write(map, data_h, ow_reg_add(map, CMD_DATA_OFS) + 2);
+		map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS) + 2);
+		map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS) + 2);
+		map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS) + 2);
+		map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS) + 2);
+	}
+
+	/* Fill Program Buffer */
+	if ((cmd_code == LPDDR2_NVM_BUF_PROGRAM) ||
+		(cmd_code == LPDDR2_NVM_BUF_OVERWRITE)) {
+		prg_buff_ofs = (map_read(map,
+			ow_reg_add(map, PRG_BUFFER_OFS))).x[0];
+		for (i = 0; i < cmd_mpr; i++) {
+			map_write(map, build_map_word(buf[i]), map->pfow_base +
+			prg_buff_ofs + i);
+		}
+	}
+
+	/* Command Execute */
+	map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS));
+	if (pcm_data->bus_width == 0x0004)	/* 2x16 devices stacked */
+		map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS) + 2);
+
+	/* Status Register Check */
+	do {
+		sr = map_read(map, ow_reg_add(map, STATUS_REG_OFS));
+		status_reg = sr.x[0];
+		if (pcm_data->bus_width == 0x0004) {/* 2x16 devices stacked */
+			sr = map_read(map, ow_reg_add(map,
+				STATUS_REG_OFS) + 2);
+			status_reg += sr.x[0]<<16;
+		}
+	} while ((status_reg&sr_ok_datamask) != sr_ok_datamask);
+
+	return (((status_reg&sr_ok_datamask) == sr_ok_datamask) ? 0 : -EIO);
+}
+
+/*
+ * Execute lpddr2-nvm operations @ block level
+ */
+static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add,
+	uint64_t len, u_char block_op)
+{
+	struct map_info *map = mtd->priv;
+	u_long add, end_add;
+	int ret = 0;
+
+	mutex_lock(&lpdd2_nvm_mutex);
+
+	ow_enable(map);
+
+	add = start_add;
+	end_add = add + len;
+
+	if ((add > mtd->size) || (end_add > mtd->size)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	do {
+		ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add, NULL);
+		if (ret)
+			goto out;
+		add += mtd->erasesize;
+	} while (add < end_add);
+
+out:
+	ow_disable(map);
+	mutex_unlock(&lpdd2_nvm_mutex);
+	return ret;
+}
+
+/*
+ * verify presence of PFOW string
+ */
+static int lpddr2_nvm_pfow_present(struct map_info *map)
+{
+	map_word pfow_val[4];
+	unsigned int found = 1;
+
+	mutex_lock(&lpdd2_nvm_mutex);
+
+	ow_enable(map);
+
+	/* Load string from array */
+	pfow_val[0] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_P));
+	pfow_val[1] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_F));
+	pfow_val[2] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_O));
+	pfow_val[3] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_W));
+
+	/* Verify the string loaded vs expected */
+	if (!map_word_equal(map, build_map_word('P'), pfow_val[0]))
+		found = 0;
+	if (!map_word_equal(map, build_map_word('F'), pfow_val[1]))
+		found = 0;
+	if (!map_word_equal(map, build_map_word('O'), pfow_val[2]))
+		found = 0;
+	if (!map_word_equal(map, build_map_word('W'), pfow_val[3]))
+		found = 0;
+
+	ow_disable(map);
+
+	mutex_unlock(&lpdd2_nvm_mutex);
+
+	return found;
+}
+
+/*
+ * lpddr2_nvm driver read method
+ */
+static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add,
+				size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	int ret = 0;
+
+	mutex_lock(&lpdd2_nvm_mutex);
+
+	*retlen = len;
+
+	if ((start_add + len) > mtd->size) {
+		pr_alert("lpddr2_nvm: read out of memory range\n");
+		*retlen = 0;
+		ret = -EINVAL;
+		goto out;
+	}
+
+	map_copy_from(map, buf, start_add, *retlen);
+
+out:
+	mutex_unlock(&lpdd2_nvm_mutex);
+	return ret;
+}
+
+/*
+ * lpddr2_nvm driver write method
+ */
+static int lpddr2_nvm_write(struct mtd_info *mtd, loff_t start_add,
+				size_t len, size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct pcm_int_data *pcm_data = map->fldrv_priv;
+	u_long add, current_len, tot_len, target_len, my_data;
+	u_char *write_buf = (u_char *)buf;
+	int ret = 0;
+
+	mutex_lock(&lpdd2_nvm_mutex);
+
+	ow_enable(map);
+
+	/* Set start value for the variables */
+	add = start_add;
+	target_len = len;
+	tot_len = 0;
+
+	if ((start_add + len) > mtd->size) {
+		pr_alert("lpddr2_nvm: write out of memory range\n");
+		*retlen = 0;
+		ret = -EINVAL;
+		goto out;
+	}
+
+	while (tot_len < target_len) {
+		if (!(IS_ALIGNED(add, mtd->writesize))) { /* do sw program */
+			my_data = write_buf[tot_len];
+			my_data += (write_buf[tot_len+1])<<8;
+			if (pcm_data->bus_width == 0x0004) {/* 2x16 devices */
+				my_data += (write_buf[tot_len+2])<<16;
+				my_data += (write_buf[tot_len+3])<<24;
+			}
+			ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_SW_OVERWRITE,
+				my_data, add, 0x00, NULL);
+			if (ret)
+				goto out;
+
+			add += pcm_data->bus_width;
+			tot_len += pcm_data->bus_width;
+		} else {		/* do buffer program */
+			current_len = min(target_len - tot_len,
+				(u_long) mtd->writesize);
+			ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_BUF_OVERWRITE,
+				0x00, add, current_len, write_buf + tot_len);
+			if (ret)
+				goto out;
+
+			add += current_len;
+			tot_len += current_len;
+		}
+	}
+
+out:
+	*retlen = tot_len;
+	ow_disable(map);
+	mutex_unlock(&lpdd2_nvm_mutex);
+	return ret;
+}
+
+/*
+ * lpddr2_nvm driver erase method
+ */
+static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	int ret = lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len,
+		LPDDR2_NVM_ERASE);
+	if (!ret) {
+		instr->state = MTD_ERASE_DONE;
+		mtd_erase_callback(instr);
+	}
+
+	return ret;
+}
+
+/*
+ * lpddr2_nvm driver unlock method
+ */
+static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add,
+	uint64_t len)
+{
+	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_UNLOCK);
+}
+
+/*
+ * lpddr2_nvm driver lock method
+ */
+static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,
+	uint64_t len)
+{
+	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK);
+}
+
+/*
+ * lpddr2_nvm driver probe method
+ */
+static int lpddr2_nvm_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct map_info *lpddr2_nvm_map;
+	struct mtd_info *lpddr2_nvm_mtd;
+	struct resource *address_range = platform_get_resource(pdev,
+						IORESOURCE_MEM, 0);
+	struct resource *control_regs = platform_get_resource(pdev,
+						IORESOURCE_MEM, 1);
+	struct resource *buswidth = platform_get_resource(pdev,
+						IORESOURCE_BUS, 0);
+	struct pcm_int_data *pcm_data;
+
+	/* Allocate memory control_regs data structures */
+	pcm_data = kzalloc(sizeof(*pcm_data), GFP_KERNEL);
+	if (!control_regs) {
+		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for int_data\n");
+		ret = 1;
+		goto out;
+	}
+	pcm_data->reg_data =	(void *) control_regs->start;
+	pcm_data->reg_cfg =	(void *) control_regs->end;
+	pcm_data->bus_width =	(int) buswidth->start;
+
+	/* Allocate memory for map_info & mtd_info data structures */
+	lpddr2_nvm_map = kzalloc(sizeof(*lpddr2_nvm_map), GFP_KERNEL);
+	if (!lpddr2_nvm_map) {
+		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for map\n");
+		ret = 1;
+		goto out;
+	}
+
+	lpddr2_nvm_mtd = kzalloc(sizeof(*lpddr2_nvm_mtd), GFP_KERNEL);
+	if (!lpddr2_nvm_mtd) {
+		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for mtd\n");
+		ret = 1;
+		goto out;
+	}
+
+	/* Reserve lpddr2_nvm address range */
+	if (request_mem_region(address_range->start, (address_range->end -
+		address_range->start + 1), "lpddr2_nvm") == NULL) {
+		pr_alert("lpddr2_nvm_probe: Unable to reserve memory address %#010x\n",
+		address_range->start);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* Populate map_info data structure */
+	*lpddr2_nvm_map = (struct map_info) {
+		.virt		= ioremap_nocache(address_range->start,
+				(address_range->end-address_range->start+1)),
+		.name		= pdev->dev.init_name,
+		.phys		= address_range->start,
+		.size		= address_range->end - address_range->start + 1,
+		.bankwidth	= pcm_data->bus_width/2,
+		.pfow_base	= OW_BASE_ADDRESS,
+		.fldrv_priv	= pcm_data,
+	};
+
+	simple_map_init(lpddr2_nvm_map);	/* fill with default methods */
+
+	/* Populate mtd_info data structure */
+	*lpddr2_nvm_mtd = (struct mtd_info) {
+		.name		= pdev->dev.init_name,
+		.type		= MTD_RAM,
+		.priv		= lpddr2_nvm_map,
+		.size		= address_range->end - address_range->start + 1,
+		.erasesize	= ERASE_BLOCKSIZE * pcm_data->bus_width,
+		.writesize	= 1,
+		.writebufsize	= WRITE_BUFFSIZE * pcm_data->bus_width,
+		.flags		= (MTD_CAP_PCM | MTD_POWERUP_LOCK),
+		._read		= lpddr2_nvm_read,
+		._read_oob	= NULL,
+		._write		= lpddr2_nvm_write,
+		._write_oob	= NULL,
+		._erase		= lpddr2_nvm_erase,
+		._unlock	= lpddr2_nvm_unlock,
+		._lock		= lpddr2_nvm_lock,
+		._sync		= NULL,
+		._suspend	= NULL,
+		._resume	= NULL,
+		._block_isbad	= NULL,
+		._block_markbad	= NULL,
+	};
+
+	/* Verify the presence of the device looking for PFOW string */
+	if (lpddr2_nvm_pfow_present(lpddr2_nvm_map)) {
+		pr_alert("lpddr2_nvm_probe: device recognized\n");
+		/* Register the mtd_partition structure */
+		if (mtd_add_partition(lpddr2_nvm_mtd, "my_pcm", 0x10000000,
+			0x00)){
+			pr_alert("lpddr2_nvm_probe: Failed to add mtd partition\n");
+			ret = 1;
+			goto out;
+		}
+		ret = 0;
+	} else {
+		pr_alert("%s: PFOW string not found at address %#010lx\n",
+			lpddr2_nvm_map->name, lpddr2_nvm_map->pfow_base);
+		ret = 1;
+	}
+
+out:
+	return ret;
+}
+
+/* Initialize platform_driver data structure for lpddr2_nvm */
+static struct platform_driver lpddr2_nvm_drv = {
+	.driver		= {
+		.name	= "lpddr2_nvm",
+	},
+	.probe		= lpddr2_nvm_probe,
+	.remove		= NULL,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+
+module_platform_driver(lpddr2_nvm_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti at gmail.com>");
+MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");
+
diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index 36eace0..33f3036 100644
--- a/include/uapi/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
@@ -109,6 +109,7 @@ struct mtd_write_req {
 #define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
 #define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)
 #define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)
+#define MTD_CAP_PCM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
 
 /* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
 #define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
-- 
1.7.9.5



From vincenzo.aliberti at gmail.com  Thu Jun 20 15:50:27 2013
From: vincenzo.aliberti at gmail.com (Vincenzo Aliberti)
Date: Thu, 20 Jun 2013 21:50:27 +0200
Subject: [PATCH] [MTD] MTD driver for LPDDR2-NVM PCM memories
In-Reply-To: <1371753473-2343-1-git-send-email-vincenzo.aliberti@gmail.com>
References: <1371753473-2343-1-git-send-email-vincenzo.aliberti@gmail.com>
Message-ID: <51C35D03.5020208@gmail.com>

I'm sending the new patch version according to your suggestion.
Thanks for your help

Below my feedback:
On Mon, Nov 12, 2012 at 5:04 PM, Artem Bityutskiy <dedekind1 at gmail.com> 
wrote:
On Tue, 2012-10-16 at 23:24 +0200, Vincenzo Aliberti wrote:
 > +/*
 > + * Internal Type Definitions
 > + * pcm_int_data contains memory controller details:
 > + * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
 > + * @reg_cfg  : LPDDR2_MODE_REG_CFG register address after remapping
 > + * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)  */
 > +struct pcm_int_data {
 > +     void __iomem *reg_data;
 > +     void __iomem *reg_cfg;
 > +     int bus_width;
 > +};
 > +
 > +static DEFINE_MUTEX(lpdd2_nvm_mutex);
A global mutes? So if you have 2 independent PCM chips handled by this 
driver, the access to them will be mutually excluded?

VA: based on my understanding systems today supporting PCM only manage 1 
chip

 > +
 > +static inline map_word build_map_word(u_long myword) {
 > +     map_word val = { {0} };
 > +     val.x[0] = myword;
 > +     return val;
 > +}
 > +
 > +static inline u_int build_mr_cfgmaks(u_int bus_width) {
 > +     u_int val = MR_CFGMASK;
 > +
 > +     if (bus_width == 0x0004)                /* x32 device */
 > +             val = val<<16;
 > +
 > +     return val;
 > +}
 > +
 > +static inline u_int build_sr_ok_datamask(u_int bus_width) {
 > +     u_int val = SR_OK_DATAMASK;
 > +
 > +     if (bus_width == 0x0004)                /* x32 device */
 > +             val = (val<<16)+val;
 > +
 > +     return val;
 > +}
How about adding some comments about what the functions above do?

VA: OK done

 > +
 > +/*
 > + * Enable lpddr2-nvm Overlay Window
 > + */
How about a short comment explaining what is the Overlay Window?
VA: OK done


 > +static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code,
 > +     u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf) {
 > +     map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} },
 > +             mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} },
 > +             exec_cmd = { {0} }, sr;
 > +     map_word data_h = { {0} };      /* only for 2x x16 devices
 > +stacked */
 > +     u_long i, status_reg, prg_buff_ofs;
 > +     struct pcm_int_data *pcm_data = map->fldrv_priv;
 > +     u_int sr_ok_datamask =
 > +build_sr_ok_datamask(pcm_data->bus_width);
 > +
 > +     /* Builds low and high words for OW Control Registers */
 > +     add_l.x[0]      = cmd_add&0x0000FFFF;
 > +     add_h.x[0]      = (cmd_add>>16)&0x0000FFFF;
 > +     mpr_l.x[0]      = cmd_mpr&0x0000FFFF;
 > +     mpr_h.x[0]      = (cmd_mpr>>16)&0x0000FFFF;
 > +     cmd.x[0]        = cmd_code&0x0000FFFF;
 > +     exec_cmd.x[0]   = 0x0001;
 > +     data_l.x[0]     = cmd_data&0x0000FFFF;
 > +     data_h.x[0]     = (cmd_data>>16)&0x0000FFFF; /* only for 2x x16
 > + */
 > +
 > +     /* Set Overlay Window Control Registers */
 > +     map_write(map, cmd,
 > + map->pfow_base+CMD_CODE_OFS*pcm_data->bus_width);
 > +     map_write(map, data_l,
 > + map->pfow_base+CMD_DATA_OFS*pcm_data->bus_width);
 > +     map_write(map, add_l,
 > + map->pfow_base+CMD_ADD_L_OFS*pcm_data->bus_width);
 > +     map_write(map, add_h,
 > + map->pfow_base+CMD_ADD_H_OFS*pcm_data->bus_width);
 > +     map_write(map, mpr_l,
 > + map->pfow_base+MPR_L_OFS*pcm_data->bus_width);
 > +     map_write(map, mpr_h,
 > + map->pfow_base+MPR_H_OFS*pcm_data->bus_width);
How about introducing a small helper inline unction for
map->pfow_base+ X * pcm_data->bus_width

It is repeated everywhere and makes driver difficult to follow, no?

Also, see the coding style about how to place spaces correctly. Make 
sure checkpatch.pl is happy or almost happy (sometimes you should ignore 
its complaints, they and not always correct).

VA: OK done



--
Best Regards,
Artem Bityutskiy

On 06/20/2013 08:37 PM, Vincenzo Aliberti wrote:
> Added Support for PCM memories with LPDDR2-NVM interface
>
> Signed-off-by: Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
> ---
>   drivers/mtd/lpddr/Kconfig      |   12 +-
>   drivers/mtd/lpddr/Makefile     |    1 +
>   drivers/mtd/lpddr/lpddr2_nvm.c |  556 ++++++++++++++++++++++++++++++++++++++++
>   include/uapi/mtd/mtd-abi.h     |    1 +
>   4 files changed, 568 insertions(+), 2 deletions(-)
>   create mode 100644 drivers/mtd/lpddr/lpddr2_nvm.c
>
> diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
> index 265f969..468f06d 100644
> --- a/drivers/mtd/lpddr/Kconfig
> +++ b/drivers/mtd/lpddr/Kconfig
> @@ -1,5 +1,5 @@
> -menu "LPDDR flash memory drivers"
> -	depends on MTD!=n
> +menu "LPDDR & LPDDR2 PCM memory drivers"
> +	depends on MTD
>   
>   config MTD_LPDDR
>   	tristate "Support for LPDDR flash chips"
> @@ -17,4 +17,12 @@ config MTD_QINFO_PROBE
>   	    Window QINFO interface, permits software to be used for entire
>   	    families of devices. This serves similar purpose of CFI on legacy
>   	    Flash products
> +
> +config MTD_LPDDR2_NVM
> +	depends on MTD
> +	tristate "Support for LPDDR2-NVM flash chips"
> +	help
> +	  This option enables support of PCM memories with a LPDDR2-NVM
> +	  (Low power double data rate 2) interface.
> +
>   endmenu
> diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile
> index da48e46..881d440 100644
> --- a/drivers/mtd/lpddr/Makefile
> +++ b/drivers/mtd/lpddr/Makefile
> @@ -4,3 +4,4 @@
>   
>   obj-$(CONFIG_MTD_QINFO_PROBE)	+= qinfo_probe.o
>   obj-$(CONFIG_MTD_LPDDR)	+= lpddr_cmds.o
> +obj-$(CONFIG_MTD_LPDDR2_NVM) += lpddr2_nvm.o
> diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c
> new file mode 100644
> index 0000000..068f95d
> --- /dev/null
> +++ b/drivers/mtd/lpddr/lpddr2_nvm.c
> @@ -0,0 +1,556 @@
> +/*
> + * LPDDR2-NVM MTD driver. This module provides read, write, erase, lock/unlock
> + * support for LPDDR2-NVM PCM memories
> + *
> + * Copyright ? 2012 Micron Technology, Inc.
> + *
> + * Vincenzo Aliberti <vincenzo.aliberti at gmail.com>
> + * Domenico Manna <domenico.manna at gmail.com>
> + * Many thanks to Andrea Vigilante for initial enabling
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/mtd/map.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/ioport.h>
> +#include <linux/sched.h>
> +
> +/* Parameters */
> +#define ERASE_BLOCKSIZE			(0x00020000/2)	/* in Word */
> +#define WRITE_BUFFSIZE			(0x00000400/2)	/* in Word */
> +#define OW_BASE_ADDRESS			0x00000000	/* OW offset */
> +
> +/* PFOW symbols address offset */
> +#define PFOW_QUERY_STRING_P		(0x0000/2)	/* in Word */
> +#define PFOW_QUERY_STRING_F		(0x0002/2)	/* in Word */
> +#define PFOW_QUERY_STRING_O		(0x0004/2)	/* in Word */
> +#define PFOW_QUERY_STRING_W		(0x0006/2)	/* in Word */
> +
> +/* OW registers address */
> +#define CMD_CODE_OFS			(0x0080/2)	/* in Word */
> +#define CMD_DATA_OFS			(0x0084/2)	/* in Word */
> +#define CMD_ADD_L_OFS			(0x0088/2)	/* in Word */
> +#define CMD_ADD_H_OFS			(0x008A/2)	/* in Word */
> +#define MPR_L_OFS			(0x0090/2)	/* in Word */
> +#define MPR_H_OFS			(0x0092/2)	/* in Word */
> +#define CMD_EXEC_OFS			(0x00C0/2)	/* in Word */
> +#define STATUS_REG_OFS			(0x00CC/2)	/* in Word */
> +#define PRG_BUFFER_OFS			(0x0010/2)	/* in Word */
> +
> +/* Datamask */
> +#define MR_CFGMASK			0x8000
> +#define SR_OK_DATAMASK			0x0080
> +
> +/* LPDDR2-NVM Commands */
> +#define LPDDR2_NVM_LOCK			0x0061
> +#define LPDDR2_NVM_UNLOCK		0x0062
> +#define LPDDR2_NVM_SW_PROGRAM		0x0041
> +#define LPDDR2_NVM_SW_OVERWRITE		0x0042
> +#define LPDDR2_NVM_BUF_PROGRAM		0x00E9
> +#define LPDDR2_NVM_BUF_OVERWRITE	0x00EA
> +#define LPDDR2_NVM_ERASE		0x0020
> +
> +/*
> + * Internal Type Definitions
> + * pcm_int_data contains memory controller details:
> + * @reg_data : LPDDR2_MODE_REG_DATA register address after remapping
> + * @reg_cfg  : LPDDR2_MODE_REG_CFG register address after remapping
> + * &bus_width: memory bus-width (eg: x16 2 Bytes, x32 4 Bytes)
> + */
> +struct pcm_int_data {
> +	void __iomem *reg_data;
> +	void __iomem *reg_cfg;
> +	int bus_width;
> +};
> +
> +static DEFINE_MUTEX(lpdd2_nvm_mutex);
> +
> +/*
> + * Build a map_word starting from an u_long
> + */
> +static inline map_word build_map_word(u_long myword)
> +{
> +	map_word val = { {0} };
> +	val.x[0] = myword;
> +	return val;
> +}
> +
> +/*
> + * Build Mode Register Configuration DataMask based on device bus-width
> + */
> +static inline u_int build_mr_cfgmask(u_int bus_width)
> +{
> +	u_int val = MR_CFGMASK;
> +
> +	if (bus_width == 0x0004)		/* x32 device */
> +		val = val<<16;
> +
> +	return val;
> +}
> +
> +/*
> + * Build Status Register OK DataMask based on device bus-width
> + */
> +static inline u_int build_sr_ok_datamask(u_int bus_width)
> +{
> +	u_int val = SR_OK_DATAMASK;
> +
> +	if (bus_width == 0x0004)		/* x32 device */
> +		val = (val<<16)+val;
> +
> +	return val;
> +}
> +
> +/*
> + * Evaluates Overlay Window Control Registers address
> + */
> +static inline u_long ow_reg_add(struct map_info *map, u_long offset)
> +{
> +	u_long val = 0;
> +	struct pcm_int_data *pcm_data = map->fldrv_priv;
> +
> +	val = map->pfow_base + offset*pcm_data->bus_width;
> +
> +	return val;
> +}
> +
> +/*
> + * Enable lpddr2-nvm Overlay Window
> + * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
> + * used by device commands as well as uservisible resources like Device Status
> + * Register, Device ID, etc
> + */
> +static inline void ow_enable(struct map_info *map)
> +{
> +	struct pcm_int_data *pcm_data = map->fldrv_priv;
> +
> +	writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
> +		pcm_data->reg_cfg);
> +	writel_relaxed(0x01, pcm_data->reg_data);
> +}
> +
> +/*
> + * Disable lpddr2-nvm Overlay Window
> + * Overlay Window is a memory mapped area containing all LPDDR2-NVM registers
> + * used by device commands as well as uservisible resources like Device Status
> + * Register, Device ID, etc
> + */
> +static inline void ow_disable(struct map_info *map)
> +{
> +	struct pcm_int_data *pcm_data = map->fldrv_priv;
> +
> +	writel_relaxed(build_mr_cfgmask(pcm_data->bus_width) | 0x18,
> +		pcm_data->reg_cfg);
> +	writel_relaxed(0x02, pcm_data->reg_data);
> +}
> +
> +/*
> + * Execute lpddr2-nvm operations
> + */
> +static int lpddr2_nvm_do_op(struct map_info *map, u_long cmd_code,
> +	u_long cmd_data, u_long cmd_add, u_long cmd_mpr, u_char *buf)
> +{
> +	map_word add_l = { {0} }, add_h = { {0} }, mpr_l = { {0} },
> +		mpr_h = { {0} }, data_l = { {0} }, cmd = { {0} },
> +		exec_cmd = { {0} }, sr;
> +	map_word data_h = { {0} };	/* only for 2x x16 devices stacked */
> +	u_long i, status_reg, prg_buff_ofs;
> +	struct pcm_int_data *pcm_data = map->fldrv_priv;
> +	u_int sr_ok_datamask = build_sr_ok_datamask(pcm_data->bus_width);
> +
> +	/* Builds low and high words for OW Control Registers */
> +	add_l.x[0]	= cmd_add&0x0000FFFF;
> +	add_h.x[0]	= (cmd_add>>16)&0x0000FFFF;
> +	mpr_l.x[0]	= cmd_mpr&0x0000FFFF;
> +	mpr_h.x[0]	= (cmd_mpr>>16)&0x0000FFFF;
> +	cmd.x[0]	= cmd_code&0x0000FFFF;
> +	exec_cmd.x[0]	= 0x0001;
> +	data_l.x[0]	= cmd_data&0x0000FFFF;
> +	data_h.x[0]	= (cmd_data>>16)&0x0000FFFF; /* only for 2x x16 */
> +
> +	/* Set Overlay Window Control Registers */
> +	map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS));
> +	map_write(map, data_l, ow_reg_add(map, CMD_DATA_OFS));
> +	map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS));
> +	map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS));
> +	map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS));
> +	map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS));
> +	if (pcm_data->bus_width == 0x0004) {	/* 2x16 devices stacked */
> +		map_write(map, cmd, ow_reg_add(map, CMD_CODE_OFS) + 2);
> +		map_write(map, data_h, ow_reg_add(map, CMD_DATA_OFS) + 2);
> +		map_write(map, add_l, ow_reg_add(map, CMD_ADD_L_OFS) + 2);
> +		map_write(map, add_h, ow_reg_add(map, CMD_ADD_H_OFS) + 2);
> +		map_write(map, mpr_l, ow_reg_add(map, MPR_L_OFS) + 2);
> +		map_write(map, mpr_h, ow_reg_add(map, MPR_H_OFS) + 2);
> +	}
> +
> +	/* Fill Program Buffer */
> +	if ((cmd_code == LPDDR2_NVM_BUF_PROGRAM) ||
> +		(cmd_code == LPDDR2_NVM_BUF_OVERWRITE)) {
> +		prg_buff_ofs = (map_read(map,
> +			ow_reg_add(map, PRG_BUFFER_OFS))).x[0];
> +		for (i = 0; i < cmd_mpr; i++) {
> +			map_write(map, build_map_word(buf[i]), map->pfow_base +
> +			prg_buff_ofs + i);
> +		}
> +	}
> +
> +	/* Command Execute */
> +	map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS));
> +	if (pcm_data->bus_width == 0x0004)	/* 2x16 devices stacked */
> +		map_write(map, exec_cmd, ow_reg_add(map, CMD_EXEC_OFS) + 2);
> +
> +	/* Status Register Check */
> +	do {
> +		sr = map_read(map, ow_reg_add(map, STATUS_REG_OFS));
> +		status_reg = sr.x[0];
> +		if (pcm_data->bus_width == 0x0004) {/* 2x16 devices stacked */
> +			sr = map_read(map, ow_reg_add(map,
> +				STATUS_REG_OFS) + 2);
> +			status_reg += sr.x[0]<<16;
> +		}
> +	} while ((status_reg&sr_ok_datamask) != sr_ok_datamask);
> +
> +	return (((status_reg&sr_ok_datamask) == sr_ok_datamask) ? 0 : -EIO);
> +}
> +
> +/*
> + * Execute lpddr2-nvm operations @ block level
> + */
> +static int lpddr2_nvm_do_block_op(struct mtd_info *mtd, loff_t start_add,
> +	uint64_t len, u_char block_op)
> +{
> +	struct map_info *map = mtd->priv;
> +	u_long add, end_add;
> +	int ret = 0;
> +
> +	mutex_lock(&lpdd2_nvm_mutex);
> +
> +	ow_enable(map);
> +
> +	add = start_add;
> +	end_add = add + len;
> +
> +	if ((add > mtd->size) || (end_add > mtd->size)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	do {
> +		ret = lpddr2_nvm_do_op(map, block_op, 0x00, add, add, NULL);
> +		if (ret)
> +			goto out;
> +		add += mtd->erasesize;
> +	} while (add < end_add);
> +
> +out:
> +	ow_disable(map);
> +	mutex_unlock(&lpdd2_nvm_mutex);
> +	return ret;
> +}
> +
> +/*
> + * verify presence of PFOW string
> + */
> +static int lpddr2_nvm_pfow_present(struct map_info *map)
> +{
> +	map_word pfow_val[4];
> +	unsigned int found = 1;
> +
> +	mutex_lock(&lpdd2_nvm_mutex);
> +
> +	ow_enable(map);
> +
> +	/* Load string from array */
> +	pfow_val[0] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_P));
> +	pfow_val[1] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_F));
> +	pfow_val[2] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_O));
> +	pfow_val[3] = map_read(map, ow_reg_add(map, PFOW_QUERY_STRING_W));
> +
> +	/* Verify the string loaded vs expected */
> +	if (!map_word_equal(map, build_map_word('P'), pfow_val[0]))
> +		found = 0;
> +	if (!map_word_equal(map, build_map_word('F'), pfow_val[1]))
> +		found = 0;
> +	if (!map_word_equal(map, build_map_word('O'), pfow_val[2]))
> +		found = 0;
> +	if (!map_word_equal(map, build_map_word('W'), pfow_val[3]))
> +		found = 0;
> +
> +	ow_disable(map);
> +
> +	mutex_unlock(&lpdd2_nvm_mutex);
> +
> +	return found;
> +}
> +
> +/*
> + * lpddr2_nvm driver read method
> + */
> +static int lpddr2_nvm_read(struct mtd_info *mtd, loff_t start_add,
> +				size_t len, size_t *retlen, u_char *buf)
> +{
> +	struct map_info *map = mtd->priv;
> +	int ret = 0;
> +
> +	mutex_lock(&lpdd2_nvm_mutex);
> +
> +	*retlen = len;
> +
> +	if ((start_add + len) > mtd->size) {
> +		pr_alert("lpddr2_nvm: read out of memory range\n");
> +		*retlen = 0;
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	map_copy_from(map, buf, start_add, *retlen);
> +
> +out:
> +	mutex_unlock(&lpdd2_nvm_mutex);
> +	return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver write method
> + */
> +static int lpddr2_nvm_write(struct mtd_info *mtd, loff_t start_add,
> +				size_t len, size_t *retlen, const u_char *buf)
> +{
> +	struct map_info *map = mtd->priv;
> +	struct pcm_int_data *pcm_data = map->fldrv_priv;
> +	u_long add, current_len, tot_len, target_len, my_data;
> +	u_char *write_buf = (u_char *)buf;
> +	int ret = 0;
> +
> +	mutex_lock(&lpdd2_nvm_mutex);
> +
> +	ow_enable(map);
> +
> +	/* Set start value for the variables */
> +	add = start_add;
> +	target_len = len;
> +	tot_len = 0;
> +
> +	if ((start_add + len) > mtd->size) {
> +		pr_alert("lpddr2_nvm: write out of memory range\n");
> +		*retlen = 0;
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	while (tot_len < target_len) {
> +		if (!(IS_ALIGNED(add, mtd->writesize))) { /* do sw program */
> +			my_data = write_buf[tot_len];
> +			my_data += (write_buf[tot_len+1])<<8;
> +			if (pcm_data->bus_width == 0x0004) {/* 2x16 devices */
> +				my_data += (write_buf[tot_len+2])<<16;
> +				my_data += (write_buf[tot_len+3])<<24;
> +			}
> +			ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_SW_OVERWRITE,
> +				my_data, add, 0x00, NULL);
> +			if (ret)
> +				goto out;
> +
> +			add += pcm_data->bus_width;
> +			tot_len += pcm_data->bus_width;
> +		} else {		/* do buffer program */
> +			current_len = min(target_len - tot_len,
> +				(u_long) mtd->writesize);
> +			ret = lpddr2_nvm_do_op(map, LPDDR2_NVM_BUF_OVERWRITE,
> +				0x00, add, current_len, write_buf + tot_len);
> +			if (ret)
> +				goto out;
> +
> +			add += current_len;
> +			tot_len += current_len;
> +		}
> +	}
> +
> +out:
> +	*retlen = tot_len;
> +	ow_disable(map);
> +	mutex_unlock(&lpdd2_nvm_mutex);
> +	return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver erase method
> + */
> +static int lpddr2_nvm_erase(struct mtd_info *mtd, struct erase_info *instr)
> +{
> +	int ret = lpddr2_nvm_do_block_op(mtd, instr->addr, instr->len,
> +		LPDDR2_NVM_ERASE);
> +	if (!ret) {
> +		instr->state = MTD_ERASE_DONE;
> +		mtd_erase_callback(instr);
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * lpddr2_nvm driver unlock method
> + */
> +static int lpddr2_nvm_unlock(struct mtd_info *mtd, loff_t start_add,
> +	uint64_t len)
> +{
> +	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_UNLOCK);
> +}
> +
> +/*
> + * lpddr2_nvm driver lock method
> + */
> +static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,
> +	uint64_t len)
> +{
> +	return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK);
> +}
> +
> +/*
> + * lpddr2_nvm driver probe method
> + */
> +static int lpddr2_nvm_probe(struct platform_device *pdev)
> +{
> +	int ret = 0;
> +	struct map_info *lpddr2_nvm_map;
> +	struct mtd_info *lpddr2_nvm_mtd;
> +	struct resource *address_range = platform_get_resource(pdev,
> +						IORESOURCE_MEM, 0);
> +	struct resource *control_regs = platform_get_resource(pdev,
> +						IORESOURCE_MEM, 1);
> +	struct resource *buswidth = platform_get_resource(pdev,
> +						IORESOURCE_BUS, 0);
> +	struct pcm_int_data *pcm_data;
> +
> +	/* Allocate memory control_regs data structures */
> +	pcm_data = kzalloc(sizeof(*pcm_data), GFP_KERNEL);
> +	if (!control_regs) {
> +		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for int_data\n");
> +		ret = 1;
> +		goto out;
> +	}
> +	pcm_data->reg_data =	(void *) control_regs->start;
> +	pcm_data->reg_cfg =	(void *) control_regs->end;
> +	pcm_data->bus_width =	(int) buswidth->start;
> +
> +	/* Allocate memory for map_info & mtd_info data structures */
> +	lpddr2_nvm_map = kzalloc(sizeof(*lpddr2_nvm_map), GFP_KERNEL);
> +	if (!lpddr2_nvm_map) {
> +		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for map\n");
> +		ret = 1;
> +		goto out;
> +	}
> +
> +	lpddr2_nvm_mtd = kzalloc(sizeof(*lpddr2_nvm_mtd), GFP_KERNEL);
> +	if (!lpddr2_nvm_mtd) {
> +		pr_alert("lpddr2_nvm_probe: Failed to allocate memory for mtd\n");
> +		ret = 1;
> +		goto out;
> +	}
> +
> +	/* Reserve lpddr2_nvm address range */
> +	if (request_mem_region(address_range->start, (address_range->end -
> +		address_range->start + 1), "lpddr2_nvm") == NULL) {
> +		pr_alert("lpddr2_nvm_probe: Unable to reserve memory address %#010x\n",
> +		address_range->start);
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	/* Populate map_info data structure */
> +	*lpddr2_nvm_map = (struct map_info) {
> +		.virt		= ioremap_nocache(address_range->start,
> +				(address_range->end-address_range->start+1)),
> +		.name		= pdev->dev.init_name,
> +		.phys		= address_range->start,
> +		.size		= address_range->end - address_range->start + 1,
> +		.bankwidth	= pcm_data->bus_width/2,
> +		.pfow_base	= OW_BASE_ADDRESS,
> +		.fldrv_priv	= pcm_data,
> +	};
> +
> +	simple_map_init(lpddr2_nvm_map);	/* fill with default methods */
> +
> +	/* Populate mtd_info data structure */
> +	*lpddr2_nvm_mtd = (struct mtd_info) {
> +		.name		= pdev->dev.init_name,
> +		.type		= MTD_RAM,
> +		.priv		= lpddr2_nvm_map,
> +		.size		= address_range->end - address_range->start + 1,
> +		.erasesize	= ERASE_BLOCKSIZE * pcm_data->bus_width,
> +		.writesize	= 1,
> +		.writebufsize	= WRITE_BUFFSIZE * pcm_data->bus_width,
> +		.flags		= (MTD_CAP_PCM | MTD_POWERUP_LOCK),
> +		._read		= lpddr2_nvm_read,
> +		._read_oob	= NULL,
> +		._write		= lpddr2_nvm_write,
> +		._write_oob	= NULL,
> +		._erase		= lpddr2_nvm_erase,
> +		._unlock	= lpddr2_nvm_unlock,
> +		._lock		= lpddr2_nvm_lock,
> +		._sync		= NULL,
> +		._suspend	= NULL,
> +		._resume	= NULL,
> +		._block_isbad	= NULL,
> +		._block_markbad	= NULL,
> +	};
> +
> +	/* Verify the presence of the device looking for PFOW string */
> +	if (lpddr2_nvm_pfow_present(lpddr2_nvm_map)) {
> +		pr_alert("lpddr2_nvm_probe: device recognized\n");
> +		/* Register the mtd_partition structure */
> +		if (mtd_add_partition(lpddr2_nvm_mtd, "my_pcm", 0x10000000,
> +			0x00)){
> +			pr_alert("lpddr2_nvm_probe: Failed to add mtd partition\n");
> +			ret = 1;
> +			goto out;
> +		}
> +		ret = 0;
> +	} else {
> +		pr_alert("%s: PFOW string not found at address %#010lx\n",
> +			lpddr2_nvm_map->name, lpddr2_nvm_map->pfow_base);
> +		ret = 1;
> +	}
> +
> +out:
> +	return ret;
> +}
> +
> +/* Initialize platform_driver data structure for lpddr2_nvm */
> +static struct platform_driver lpddr2_nvm_drv = {
> +	.driver		= {
> +		.name	= "lpddr2_nvm",
> +	},
> +	.probe		= lpddr2_nvm_probe,
> +	.remove		= NULL,
> +	.suspend	= NULL,
> +	.resume		= NULL,
> +};
> +
> +module_platform_driver(lpddr2_nvm_drv);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Vincenzo Aliberti <vincenzo.aliberti at gmail.com>");
> +MODULE_DESCRIPTION("MTD driver for LPDDR2-NVM PCM memories");
> +
> diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
> index 36eace0..33f3036 100644
> --- a/include/uapi/mtd/mtd-abi.h
> +++ b/include/uapi/mtd/mtd-abi.h
> @@ -109,6 +109,7 @@ struct mtd_write_req {
>   #define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
>   #define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)
>   #define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)
> +#define MTD_CAP_PCM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
>   
>   /* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
>   #define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)



From vapier at gentoo.org  Thu Jun 20 21:55:35 2013
From: vapier at gentoo.org (Mike Frysinger)
Date: Thu, 20 Jun 2013 21:55:35 -0400
Subject: [PATCH v3 1/1] ubi: Introduce block devices for UBI volumes
In-Reply-To: <1368887515-10536-2-git-send-email-ezequiel.garcia@free-electrons.com>
References: <1368887515-10536-1-git-send-email-ezequiel.garcia@free-electrons.com>
 <1368887515-10536-2-git-send-email-ezequiel.garcia@free-electrons.com>
Message-ID: <201306202155.37322.vapier@gentoo.org>

On Saturday 18 May 2013 10:31:54 Ezequiel Garcia wrote:

hmm, i've only written a gendisk driver once, and that was many years ago (and 
it was pretty shitty, so let's pretend i didn't at all).  so i won't be able 
to say too much on that front.

> --- a/drivers/mtd/ubi/Kconfig
> +++ b/drivers/mtd/ubi/Kconfig
> 
> +config MTD_UBI_BLOCK
> +	bool "Block device access to UBI volumes"
> +	default n
> +	help
> +	   Since UBI already takes care of eraseblock wear leveling
> +	   and bad block handling, it's possible to implement a block
> +	   device on top of it and therefore mount regular filesystems
> +	   (i.e. not flash-oriented, as ext4).
> +
> +	   In other words, this is a software flash translation layer.
> +
> +	   If in doubt, say "N".

might be useful to mention that this is built into the main ubi module, and 
you can use `ubiblkvol` to manage volumes at runtime.

> --- /dev/null
> +++ b/drivers/mtd/ubi/block.c
>
> + * Copyright (c) 2012 Ezequiel Garcia
> + * Copyright (c) 2011 Free Electrons

it's now 2013 :)

> +/* Maximum length of the 'block=' parameter */
> +#define UBIBLOCK_PARAM_LEN 64

not entirely true, but maybe doesn't matter.  max length is 63 as it includes 
\0 in the 64 byte count ;).

> +static int __init ubiblock_set_param(const char *val,
> +				     const struct kernel_param *kp)
> +{
> +	int len, i, ret;

len should be size_t (since you assign strnlen() to it and that returns a 
size_t)

> +	if (len == 0) {
> +		ubi_warn("block: empty 'blk=' parameter - ignored\n");

i think this should be block= rather than blk=

> +MODULE_PARM_DESC(block, "Attach block devices to UBI volumes.");

add a short description to the block= format ?  you had a good snippet in the 
init func above in one of the comments.

> +/*
> + * A bunch of examples worth a thousand words.

move to the top of the file ?  i personally find it more useful when they live 
there, but maybe my expectations are off.

> +static int ubiblock_fill_cache(struct ubiblock *dev, int leb_num,
> +			       struct ubiblock_cache *cache,
> +			       struct ubiblock_cache *aux_cache)
> +{
> ...
> +		/*
> +		 * Maybe it's possible to flip pointers instead of
> +		 * memcpy'ing, but let's try to keep it simple for now.
> +		 */
> +		aux_cache->leb_num = -1;
> +		aux_cache->state = STATE_EMPTY;
> +		memcpy(cache->buffer, aux_cache->buffer, dev->leb_size);

yeah, trying to see if we could eliminate some of these memcpy's would be a 
nice future enhancement

> +		/*
> +		 * If leb is not on write cache, we flush current cached

usually people say "in cache" rather than "on cache".  this comes up in a few 
comments in this file.

> +#else
> +static int ubiblock_flush(struct ubiblock *dev, bool sync)
> +{
> +	return -EPERM;
> +}
> +
> +static int ubiblock_write(struct ubiblock *dev, const char *buffer,
> +              int pos, int len)
> +{
> +	return -EPERM;
> +}
> +#endif

i think you can just do:
# define ubiblock_flush NULL
# define ubiblock_write NULL

then the common layers will do the right thing when it sees these funcs don't 
exist for this device

> +static int ubiblock_read(struct ubiblock *dev, char *buffer,
> +			 int pos, int len)
> +{
> +	int leb, offset, ret;
> +	int bytes_left = len;
> +	int to_read = len;
> +	char *cache_buffer;
> +
> +	/* Get leb:offset address to read from */
> +	leb = pos / dev->leb_size;
> +	offset = pos % dev->leb_size;
> +
> +	while (bytes_left) {
> +
> +		/*
> +		 * We can only read one leb at a time.
> +		 * Therefore if the read length is larger than
> +		 * one leb size, we split the operation.
> +		 */
> +		if (offset + to_read > dev->leb_size)
> +			to_read = dev->leb_size - offset;
> +
> +		/*
> +		 * 1) First try on read cache, if not there...
> +		 * 2) then try on write cache, if not there...
> +		 * 3) finally load this leb on read_cache
> +		 *
> +		 * Note that reading never flushes to disk!
> +		 */
> +		if (leb_on_cache(&dev->read_cache, leb)) {
> +			cache_buffer = dev->read_cache.buffer;
> +
> +#ifdef CONFIG_MTD_UBI_BLOCK_WRITE_SUPPORT
> +		} else if (leb_on_cache(&dev->write_cache, leb)) {
> +			cache_buffer = dev->write_cache.buffer;
> +#endif
> +
> +		} else {
> +			/* Leb is not in any cache: fill read_cache */
> +			ret = ubiblock_fill_cache(dev, leb,
> +				&dev->read_cache, NULL);
> +			if (ret)
> +				return ret;
> +			cache_buffer = dev->read_cache.buffer;
> +		}

i've read this code a few times but haven't been able to convince myself that 
the coherency is correct.  in the write func, you check the write cache, but 
not the read cache.  so what happens if you read from say block 0, then write 
to it, then read from it ?  where does the read cache get synced to the write 
cache ?  or would this scenario return stale data from the read cache ?

> +static void ubiblock_do_work(struct work_struct *work)
> +{
> +	struct ubiblock *dev =
> +		container_of(work, struct ubiblock, work);
> +	struct request_queue *rq = dev->rq;
> +	struct request *req;
> +	int res;
> +
> +	spin_lock_irq(rq->queue_lock);

i thought work queues could sleep ?  so you could use a regular mutex here 
rather than a spinlock ?

> +static int ubiblock_open(struct block_device *bdev, fmode_t mode)
> +{
> +	struct ubiblock *dev = bdev->bd_disk->private_data;
> +	int ubi_mode = UBI_READONLY;
> +	int ret;
> +#ifdef CONFIG_MTD_UBI_BLOCK_WRITE_SUPPORT
> +	const bool allow_write = true;
> +#else
> +	const bool allow_write = false;
> +#endif
> +
> +	mutex_lock(&dev->vol_mutex);
> +	if (dev->refcnt > 0) {
> +		/*
> +		 * The volume is already opened,
> +		 * just increase the reference counter
> +		 *
> +		 * If the first user has oppened this as read-only,
> +		 * we don't allow to open as read-write.
> +		 * This is the simplest solution. A better one would
> +		 * be to re-open the volume as writable and allocate
> +		 * the write-cache.
> +		 */
> +		if ((mode & FMODE_WRITE) &&
> +		    (dev->desc->mode != UBI_READWRITE)) {
> +			ret = -EBUSY;
> +			goto out_unlock;
> +		}
> +		dev->refcnt++;
> +		mutex_unlock(&dev->vol_mutex);
> +		return 0;
> +	}

not a big deal, but this could probably just jump to the end (where you have 
the same finishing code)

> +	if (allow_write && ubi_mode == UBI_READWRITE) {
> +		ret = ubiblock_alloc_cache(&dev->write_cache, dev->leb_size);
> +		if (ret) {
> +			ubiblock_free_cache(&dev->read_cache);
> +			goto out_free;
> +		}
> +	}
> ....
> +static void ubiblock_release(struct gendisk *gd, fmode_t mode)
> +{
> +	struct ubiblock *dev = gd->private_data;
> +
> +	mutex_lock(&dev->vol_mutex);
> +
> +	dev->refcnt--;
> +	if (dev->refcnt == 0) {
> +		ubiblock_flush(dev, true);
> +
> +		ubiblock_free_cache(&dev->read_cache);
> +		ubiblock_free_cache(&dev->write_cache);

hmm, in the open call, you only alloc the write cache when the device gets 
opened read/write.  what if it gets opened r/o and then closed ?  won't this 
free barf ?  similarly, if read/write support is compiled out ...

> +	/*
> +	 * Blocks devices needs to be attached to volumes explicitly

Blocks -> Block

> --- a/drivers/mtd/ubi/cdev.c
> +++ b/drivers/mtd/ubi/cdev.c
> 
> +	/* Attach a block device to an UBI volume */
> +	case UBI_IOCVOLATTBLK:
> +	{
> +		struct ubi_volume_info vi;
> +
> +		ubi_get_volume_info(desc, &vi);
> +		err = ubiblock_add(&vi);
> +		break;
> +	}
> +
> +	/* Dettach a block device from an UBI volume */
> +	case UBI_IOCVOLDETBLK:
> +	{
> +		struct ubi_volume_info vi;
> +
> +		ubi_get_volume_info(desc, &vi);
> +		ubiblock_del(&vi);
> +		break;
> +	}

hmm, this always returns 0.  would be nice if ubiblock_del() returned a value 
that this could pass back up to userspace.  i managed to confuse myself by 
running a few times:
	# ubiblkvol -d /dev/ubi0_0
it never issued an error/warning, and returned 0 all the time.  might be 
problematic if you have code that wants to make sure it has detached all block 
devices already ...
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130620/d2b2027c/attachment.sig>

From mpfj-list at newflow.co.uk  Fri Jun 21 08:58:11 2013
From: mpfj-list at newflow.co.uk (Mark Jackson)
Date: Fri, 21 Jun 2013 13:58:11 +0100
Subject: 3.10.0-rc4: jffs2: Possible circular locking dependency detected
In-Reply-To: <51C2FC56.1070808@newflow.co.uk>
References: <51C2FC56.1070808@newflow.co.uk>
Message-ID: <51C44DE3.3000202@newflow.co.uk>

On 20/06/13 13:57, Mark Jackson wrote:
> Just mounted a JFFS2 partition (held in NOR flash on a custom AM335x
> CPU board), and I always get the following:-
> 
> [    3.864244]
> [    3.865851] ======================================================
> [    3.872359] [ INFO: possible circular locking dependency detected ]
> [    3.878968] 3.10.0-rc4-00172-gf31c62e-dirty #249 Not tainted
> [    3.884926] -------------------------------------------------------
> [    3.891526] rcS/507 is trying to acquire lock:
> [    3.896206]  (&mm->mmap_sem){++++++}, at: [<c00b42c8>] might_fault+0x3c/0x94
> [    3.903684]
> [    3.903684] but task is already holding lock:
> [    3.909826]  (&f->sem){+.+.+.}, at: [<c016f208>] jffs2_readdir+0x40/0x1b0
> [    3.917021]
> [    3.917021] which lock already depends on the new lock.

Looks like I reported something similar earlier this year:-

http://lists.infradead.org/pipermail/linux-mtd/2013-February/045888.html

And I also found this going back to 3.0.18:-

http://www.spinics.net/lists/linux-rt-users/msg07617.html




From pekon at ti.com  Sat Jun 22 17:03:47 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 02:33:47 +0530
Subject: [PATCH v3 1/4] mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC
 configurations in device_probe
In-Reply-To: <1371935030-20773-1-git-send-email-pekon@ti.com>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
Message-ID: <1371935030-20773-2-git-send-email-pekon@ti.com>

From: "Gupta, Pekon" <pekon at ti.com>

ECC scheme on NAND devices can be implemented in multiple ways.Some using
Software algorithm, while others using in-build Hardware engines.
omap2-nand driver currently supports following flavours of ECC schemes.

+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_ECC_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_OMAP_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+

This patch
- separates the configurations for various ECC schemes.
- fixes dependency issues based on Kconfig options.
- cleans up redundant code

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 drivers/mtd/nand/omap2.c          | 504 +++++++++++++++++++-------------------
 include/linux/platform_data/elm.h |   4 +
 2 files changed, 252 insertions(+), 256 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 81b80af..b525060 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -25,8 +25,10 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 #include <linux/bch.h>
+#endif
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/platform_data/elm.h>
 #endif
 
@@ -141,6 +143,9 @@
 #define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
 #define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
 
+#define BADBLOCK_MARKER_LENGTH		0x2
+#define OMAP_ECC_BCH8_POLYNOMIAL	0x201b
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -182,14 +187,11 @@ struct omap_nand_info {
 	u_char				*buf;
 	int					buf_len;
 	struct gpmc_nand_regs		reg;
-
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-	struct bch_control             *bch;
-	struct nand_ecclayout           ecclayout;
+	/* fields specific for BCHx_HW ECC scheme */
+	struct bch_control              *bch;
 	bool				is_elm_used;
 	struct device			*elm_dev;
 	struct device_node		*of_node;
-#endif
 };
 
 /**
@@ -1058,8 +1060,6 @@ static int omap_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-
 /**
  * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
  * @mtd: MTD device structure
@@ -1141,6 +1141,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
 }
 
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 /**
  * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
  * @mtd: MTD device structure
@@ -1227,6 +1228,62 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
 }
 
 /**
+ * omap3_correct_data_bch - Decode received data and correct errors
+ * @mtd: MTD device structure
+ * @data: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ */
+static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
+				  u_char *read_ecc, u_char *calc_ecc)
+{
+	int i, count;
+	/* cannot correct more than 8 errors */
+	unsigned int errloc[8];
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+						   mtd);
+
+	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
+			   errloc);
+	if (count > 0) {
+		/* correct errors */
+		for (i = 0; i < count; i++) {
+			/* correct data only, not ecc bytes */
+			if (errloc[i] < 8*512)
+				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
+			pr_debug("corrected bitflip %u\n", errloc[i]);
+		}
+	} else if (count < 0) {
+		pr_err("ecc unrecoverable error\n");
+	}
+	return count;
+}
+
+/**
+ * omap3_free_bch - Release BCH ecc resources
+ * @mtd: MTD device structure
+ */
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+						   mtd);
+	if (info->bch) {
+		free_bch(info->bch);
+		info->bch = NULL;
+	}
+}
+
+#else
+
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_BCH */
+
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+/**
  * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
  * @mtd:	MTD device structure
  * @dat:	The pointer to data on which ecc is computed
@@ -1519,38 +1576,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
 }
 
 /**
- * omap3_correct_data_bch - Decode received data and correct errors
- * @mtd: MTD device structure
- * @data: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- */
-static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
-				  u_char *read_ecc, u_char *calc_ecc)
-{
-	int i, count;
-	/* cannot correct more than 8 errors */
-	unsigned int errloc[8];
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-
-	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
-			   errloc);
-	if (count > 0) {
-		/* correct errors */
-		for (i = 0; i < count; i++) {
-			/* correct data only, not ecc bytes */
-			if (errloc[i] < 8*512)
-				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
-			pr_debug("corrected bitflip %u\n", errloc[i]);
-		}
-	} else if (count < 0) {
-		pr_err("ecc unrecoverable error\n");
-	}
-	return count;
-}
-
-/**
  * omap_write_page_bch - BCH ecc based write page function for entire page
  * @mtd:		mtd info structure
  * @chip:		nand chip info structure
@@ -1637,197 +1662,47 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * omap3_free_bch - Release BCH ecc resources
- * @mtd: MTD device structure
- */
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	if (info->bch) {
-		free_bch(info->bch);
-		info->bch = NULL;
-	}
-}
-
-/**
- * omap3_init_bch - Initialize BCH ECC
- * @mtd: MTD device structure
- * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
+ * is_elm_present - checks for presence of ELM module by scanning DT nodes
+ * @omap_nand_info: NAND device structure containing platform data
+ * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
  */
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
+static int is_elm_present(struct omap_nand_info *info, int bch_type)
 {
-	int max_errors;
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-#ifdef CONFIG_MTD_NAND_OMAP_BCH8
-	const int hw_errors = BCH8_MAX_ERROR;
-#else
-	const int hw_errors = BCH4_MAX_ERROR;
-#endif
-	enum bch_ecc bch_type;
 	const __be32 *parp;
 	int lenp;
 	struct device_node *elm_node;
-
-	info->bch = NULL;
-
-	max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
-		BCH8_MAX_ERROR : BCH4_MAX_ERROR;
-	if (max_errors != hw_errors) {
-		pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
-		       max_errors, hw_errors);
-		goto fail;
-	}
-
-	info->nand.ecc.size = 512;
-	info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
-	info->nand.ecc.mode = NAND_ECC_HW;
-	info->nand.ecc.strength = max_errors;
-
-	if (hw_errors == BCH8_MAX_ERROR)
-		bch_type = BCH8_ECC;
-	else
-		bch_type = BCH4_ECC;
+	struct platform_device *pdev;
+	info->is_elm_used = false;
 
 	/* Detect availability of ELM module */
 	parp = of_get_property(info->of_node, "elm_id", &lenp);
 	if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
 		pr_err("Missing elm_id property, fall back to Software BCH\n");
-		info->is_elm_used = false;
 	} else {
-		struct platform_device *pdev;
-
 		elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
 		pdev = of_find_device_by_node(elm_node);
 		info->elm_dev = &pdev->dev;
-
-		if (elm_config(info->elm_dev, bch_type) == 0)
-			info->is_elm_used = true;
-	}
-
-	if (info->is_elm_used && (mtd->writesize <= 4096)) {
-
-		if (hw_errors == BCH8_MAX_ERROR)
-			info->nand.ecc.bytes = BCH8_SIZE;
-		else
-			info->nand.ecc.bytes = BCH4_SIZE;
-
-		info->nand.ecc.correct = omap_elm_correct_data;
-		info->nand.ecc.calculate = omap3_calculate_ecc_bch;
-		info->nand.ecc.read_page = omap_read_page_bch;
-		info->nand.ecc.write_page = omap_write_page_bch;
-	} else {
-		/*
-		 * software bch library is only used to detect and
-		 * locate errors
-		 */
-		info->bch = init_bch(13, max_errors,
-				0x201b /* hw polynomial */);
-		if (!info->bch)
-			goto fail;
-
-		info->nand.ecc.correct = omap3_correct_data_bch;
-
-		/*
-		 * The number of corrected errors in an ecc block that will
-		 * trigger block scrubbing defaults to the ecc strength (4 or 8)
-		 * Set mtd->bitflip_threshold here to define a custom threshold.
-		 */
-
-		if (max_errors == 8) {
-			info->nand.ecc.bytes = 13;
-			info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
-		} else {
-			info->nand.ecc.bytes = 7;
-			info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
-		}
-	}
-
-	pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
-	return 0;
-fail:
-	omap3_free_bch(mtd);
-	return -1;
-}
-
-/**
- * omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
- * @mtd: MTD device structure
- */
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-	int i, steps, offset;
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	struct nand_ecclayout *layout = &info->ecclayout;
-
-	/* build oob layout */
-	steps = mtd->writesize/info->nand.ecc.size;
-	layout->eccbytes = steps*info->nand.ecc.bytes;
-
-	/* do not bother creating special oob layouts for small page devices */
-	if (mtd->oobsize < 64) {
-		pr_err("BCH ecc is not supported on small page devices\n");
-		goto fail;
-	}
-
-	/* reserve 2 bytes for bad block marker */
-	if (layout->eccbytes+2 > mtd->oobsize) {
-		pr_err("no oob layout available for oobsize %d eccbytes %u\n",
-		       mtd->oobsize, layout->eccbytes);
-		goto fail;
+		/* ELM module available, now configure it */
+		elm_config(info->elm_dev, bch_type);
+		info->is_elm_used = true;
+		return 0;
 	}
 
-	/* ECC layout compatible with RBL for BCH8 */
-	if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-		offset = 2;
-	else
-		offset = mtd->oobsize - layout->eccbytes;
-
-	/* put ecc bytes at oob tail */
-	for (i = 0; i < layout->eccbytes; i++)
-		layout->eccpos[i] = offset + i;
-
-	if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-		layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
-	else
-		layout->oobfree[0].offset = 2;
-
-	layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
-	info->nand.ecc.layout = layout;
-
-	if (!(info->nand.options & NAND_BUSWIDTH_16))
-		info->nand.badblock_pattern = &bb_descrip_flashbased;
-	return 0;
-fail:
-	omap3_free_bch(mtd);
-	return -1;
-}
-
-#else
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
-{
-	pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
-	return -1;
-}
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-	return -1;
-}
-static void omap3_free_bch(struct mtd_info *mtd)
-{
+	return -ENODEV;
 }
 #endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info		*info;
 	struct omap_nand_platform_data	*pdata;
+	struct mtd_info			*mtd;
+	struct nand_chip		*chip;
 	int				err;
-	int				i, offset;
-	dma_cap_mask_t mask;
-	unsigned sig;
+	int				i;
+	dma_cap_mask_t			mask;
+	unsigned			sig;
 	struct resource			*res;
 	struct mtd_part_parser_data	ppdata = {};
 
@@ -1846,16 +1721,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
-	info->pdev = pdev;
+	mtd			= &info->mtd;
+	mtd->name		= dev_name(&pdev->dev);
+	mtd->owner		= THIS_MODULE;
+	mtd->priv		= &info->nand;
+	chip			= mtd->priv;
 
+	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
 	info->reg		= pdata->reg;
+	info->bch		= NULL;
 
-	info->mtd.priv		= &info->nand;
-	info->mtd.name		= dev_name(&pdev->dev);
-	info->mtd.owner		= THIS_MODULE;
-
-	info->nand.options	= pdata->devsize;
+	info->nand.options	= NAND_BUSWIDTH_AUTO;
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 	info->of_node		= pdata->of_node;
@@ -1903,6 +1780,31 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->nand.chip_delay = 50;
 	}
 
+	/* scan NAND device conncted to controller */
+	if (nand_scan_ident(mtd, 1, NULL)) {
+		err = -ENXIO;
+		goto out_release_mem_region;
+	}
+	pr_info("%s: detected %s NAND flash\n", DRIVER_NAME,
+			(info->nand.options & NAND_BUSWIDTH_16) ? "x16" : "x8");
+	if ((info->nand.options & NAND_BUSWIDTH_16) !=
+			(pdata->devsize & NAND_BUSWIDTH_16)) {
+		pr_err("%s: but incorrectly configured as %s", DRIVER_NAME,
+			(pdata->devsize & NAND_BUSWIDTH_16) ? "x16" : "x8");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+	/* check for small page devices */
+	if ((mtd->oobsize < 64) &&
+		(pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_DEFAULT) &&
+		(pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_HW)) {
+		pr_err("small page devices are not supported\n");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+	/* populate read & write API based on xfer_type selected */
 	switch (pdata->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		info->nand.read_buf   = omap_read_buf_pref;
@@ -1992,66 +1894,154 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto out_release_mem_region;
 	}
 
-	/* select the ecc type */
-	if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
-		info->nand.ecc.mode = NAND_ECC_SOFT;
-	else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
-		(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
+	/* populate MTD interface based on ECC scheme */
+	switch (pdata->ecc_opt) {
+	case OMAP_ECC_HAMMING_CODE_DEFAULT:
+		pr_info("using OMAP_ECC_HAMMING_CODE_DEFAULT ECC scheme\n");
+		info->nand.ecc.mode		= NAND_ECC_SOFT;
+		goto generic_ecc_layout;
+
+	case OMAP_ECC_HAMMING_CODE_HW:
+		pr_info("using OMAP_ECC_HAMMING_CODE_HW ECC scheme\n");
+		info->nand.ecc.mode             = NAND_ECC_HW;
 		info->nand.ecc.bytes            = 3;
 		info->nand.ecc.size             = 512;
 		info->nand.ecc.strength         = 1;
 		info->nand.ecc.calculate        = omap_calculate_ecc;
 		info->nand.ecc.hwctl            = omap_enable_hwecc;
 		info->nand.ecc.correct          = omap_correct_data;
+		goto generic_ecc_layout;
+
+	case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+		pr_info("using OMAP_ECC_HAMMING_CODE_HW_ROMCODE ECC scheme\n");
 		info->nand.ecc.mode             = NAND_ECC_HW;
-	} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-		   (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-		err = omap3_init_bch(&info->mtd, pdata->ecc_opt);
-		if (err) {
+		info->nand.ecc.bytes            = 3;
+		info->nand.ecc.size             = 512;
+		info->nand.ecc.strength         = 1;
+		info->nand.ecc.calculate        = omap_calculate_ecc;
+		info->nand.ecc.hwctl            = omap_enable_hwecc;
+		info->nand.ecc.correct          = omap_correct_data;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_oobinfo.eccpos[0]	= BADBLOCK_MARKER_LENGTH;
+		else
+			omap_oobinfo.eccpos[0]	= 1;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
+							omap_oobinfo.eccbytes;
+		goto custom_ecc_layout;
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+	case OMAP_ECC_BCH8_CODE_HW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+			pr_err("ELM module not detected, required for ECC\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-	}
-
-	/* DIP switches on some boards change between 8 and 16 bit
-	 * bus widths for flash.  Try the other width if the first try fails.
-	 */
-	if (nand_scan_ident(&info->mtd, 1, NULL)) {
-		info->nand.options ^= NAND_BUSWIDTH_16;
-		if (nand_scan_ident(&info->mtd, 1, NULL)) {
-			err = -ENXIO;
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 13 + 1;
+		info->nand.ecc.strength		= 8;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap_elm_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
+		info->nand.ecc.read_page	= omap_read_page_bch;
+		info->nand.ecc.write_page	= omap_write_page_bch;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= BADBLOCK_MARKER_LENGTH;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
+							omap_oobinfo.eccbytes;
+		goto custom_ecc_layout;
+#endif
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW ECC\n");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 13;
+		info->nand.ecc.strength		= 8;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch8;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+							omap_oobinfo.eccbytes;
+		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
+		/* software bch library is used for locating errors */
+		info->bch = init_bch(info->nand.ecc.bytes,
+					info->nand.ecc.strength,
+					OMAP_ECC_BCH8_POLYNOMIAL);
+		if (!info->bch) {
+			pr_err("unable initialize S/W BCH logic\n");
+			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-	}
-
-	/* rom code layout */
-	if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
-
-		if (info->nand.options & NAND_BUSWIDTH_16)
-			offset = 2;
-		else {
-			offset = 1;
-			info->nand.badblock_pattern = &bb_descrip_flashbased;
-		}
-		omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16);
-		for (i = 0; i < omap_oobinfo.eccbytes; i++)
-			omap_oobinfo.eccpos[i] = i+offset;
-
-		omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->length = info->mtd.oobsize -
-					(offset + omap_oobinfo.eccbytes);
-
-		info->nand.ecc.layout = &omap_oobinfo;
-	} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-		   (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-		/* build OOB layout for BCH ECC correction */
-		err = omap3_init_bch_tail(&info->mtd);
-		if (err) {
+		goto custom_ecc_layout;
+
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC\n");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 7;
+		info->nand.ecc.strength		= 4;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+							omap_oobinfo.eccbytes;
+		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
+		/* software bch library is used for locating errors */
+		info->bch = init_bch(info->nand.ecc.bytes,
+					info->nand.ecc.strength,
+					OMAP_ECC_BCH8_POLYNOMIAL);
+		if (!info->bch) {
+			pr_err("unable initialize S/W BCH logic\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
+		goto custom_ecc_layout;
+#endif
+	default:
+		pr_err("selected ECC scheme not supported or not enabled\n");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+custom_ecc_layout:
+	/* populate remaining info for custom ecc layout */
+	pr_info("%s: using custom ecc layout\n", DRIVER_NAME);
+	omap_oobinfo.oobfree->length = mtd->oobsize - BADBLOCK_MARKER_LENGTH
+						- omap_oobinfo.eccbytes;
+	if (!(info->nand.options & NAND_BUSWIDTH_16))
+		info->nand.badblock_pattern = &bb_descrip_flashbased;
+	for (i = 1; i < omap_oobinfo.eccbytes; i++)
+		omap_oobinfo.eccpos[i] = omap_oobinfo.eccpos[0] + i;
+
+	/* check if NAND OOBSIZE meets ECC scheme requirement */
+	if (mtd->oobsize < (omap_oobinfo.eccbytes +
+					BADBLOCK_MARKER_LENGTH)) {
+		pr_err("not enough OOB bytes required = %d, available=%d\n",
+		       mtd->oobsize, omap_oobinfo.eccbytes);
+		err = -EINVAL;
+		goto out_release_mem_region;
 	}
+	info->nand.ecc.layout = &omap_oobinfo;
 
+generic_ecc_layout:
 	/* second phase scan */
 	if (nand_scan_tail(&info->mtd)) {
 		err = -ENXIO;
@@ -2075,11 +2065,13 @@ out_release_mem_region:
 		free_irq(info->gpmc_irq_fifo, info);
 	release_mem_region(info->phys_base, info->mem_size);
 out_free_info:
+	omap3_free_bch(&info->mtd);
 	kfree(info);
 
 	return err;
 }
 
+
 static int omap_nand_remove(struct platform_device *pdev)
 {
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h
index bf0a83b..5e36e42 100644
--- a/include/linux/platform_data/elm.h
+++ b/include/linux/platform_data/elm.h
@@ -23,6 +23,10 @@ enum bch_ecc {
 	BCH8_ECC,
 };
 
+#define ECC_TYPE_BCH4                (0x0 << 0)
+#define ECC_TYPE_BCH8                (0x1 << 0)
+#define ECC_TYPE_BCH16               (0x2 << 0)
+
 /* ELM support 8 error syndrome process */
 #define ERROR_VECTOR_MAX		8
 
-- 
1.8.1



From pekon at ti.com  Sat Jun 22 17:03:48 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 02:33:48 +0530
Subject: [PATCH v3 2/4] ARM: OMAP2+: cleaned-up DT support of various ECC
 schemes
In-Reply-To: <1371935030-20773-1-git-send-email-pekon@ti.com>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
Message-ID: <1371935030-20773-3-git-send-email-pekon@ti.com>

From: "Gupta, Pekon" <pekon at ti.com>

ECC scheme on NAND devices can be implemented in multiple ways.Some using
Software algorithm, while others using in-build Hardware engines.
omap2-nand driver currently supports following flavours of ECC schemes,
selectable via DTB.

+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_ECC_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_OMAP_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+

Selection of some ECC schemes also require enabling following Kconfig options.
This was done to optimize footprint of omap2-nand driver.
-Kconfig:CONFIG_MTD_NAND_ECC_BCH	enables S/W based BCH ECC algorithm
-Kconfig:CONFIG_MTD_NAND_OMAP_BCH	enables H/W based BCH ECC algorithm

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 .../devicetree/bindings/mtd/gpmc-nand.txt          | 44 ++++++++++++++++------
 arch/arm/mach-omap2/gpmc.c                         | 14 ++++---
 include/linux/platform_data/mtd-nand-omap2.h       | 22 +++++++----
 3 files changed, 56 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 6a983c1..690070e 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -17,20 +17,42 @@ Required properties:
 
 Optional properties:
 
- - nand-bus-width: 		Set this numeric value to 16 if the hardware
-				is wired that way. If not specified, a bus
-				width of 8 is assumed.
+ - nand-bus-width: 		Determines data-width of the connected device
+				x16 = "16"
+				x8  = "8" (default)
 
- - ti,nand-ecc-opt:		A string setting the ECC layout to use. One of:
 
-		"sw"		Software method (default)
-		"hw"		Hardware method
-		"hw-romcode"	gpmc hamming mode method & romcode layout
-		"bch4"		4-bit BCH ecc code
-		"bch8"		8-bit BCH ecc code
+ - ti,nand-ecc-opt:		Determines the ECC scheme used by driver.
+				It can be any of the following strings:
+
+	"hamming_code_sw"		1-bit Hamming ECC
+					- ECC calculation in software
+					- Error detection in software
+
+	"hamming_code_hw"		1-bit Hamming ECC
+					- ECC calculation in hardware
+					- Error detection in software
+
+	"hamming_code_hw_romcode"	1-bit Hamming ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- ECC layout compatible to ROM code
+
+	"bch8_hw_code_detection_sw"	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- depends on CONFIG_MTD_NAND_ECC_BCH
+
+	"bch8_code_hw"             	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in hardware
+					- depends on CONFIG_MTD_NAND_OMAP_BCH
+					- requires <elm_id> to be specified
+
+
+ - elm_id:			Specifies elm device node. This is required to
+				support some BCH ECC schemes mentioned above.
 
- - elm_id:	Specifies elm device node. This is required to support BCH
- 		error correction using ELM module.
 
 For inline partiton table parsing (optional):
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 6c4da12..ae8bb70 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1338,11 +1338,13 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 #ifdef CONFIG_MTD_NAND
 
 static const char * const nand_ecc_opts[] = {
-	[OMAP_ECC_HAMMING_CODE_DEFAULT]		= "sw",
-	[OMAP_ECC_HAMMING_CODE_HW]		= "hw",
-	[OMAP_ECC_HAMMING_CODE_HW_ROMCODE]	= "hw-romcode",
-	[OMAP_ECC_BCH4_CODE_HW]			= "bch4",
-	[OMAP_ECC_BCH8_CODE_HW]			= "bch8",
+	[OMAP_ECC_HAMMING_CODE_DEFAULT]		= "hamming_code_sw",
+	[OMAP_ECC_HAMMING_CODE_HW]		= "hamming_code_hw",
+	[OMAP_ECC_HAMMING_CODE_HW_ROMCODE]	= "hamming_code_hw_romcode",
+	[OMAP_ECC_BCH4_CODE_HW]			= "bch4_code_hw",
+	[OMAP_ECC_BCH4_CODE_HW_DETECTION_SW]	= "bch4_code_hw_detection_sw",
+	[OMAP_ECC_BCH8_CODE_HW]			= "bch8_code_hw",
+	[OMAP_ECC_BCH8_CODE_HW_DETECTION_SW]	= "bch8_code_hw_detection_sw"
 };
 
 static int gpmc_probe_nand_child(struct platform_device *pdev,
@@ -1369,7 +1371,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
 
 	if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
 		for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
-			if (!strcasecmp(s, nand_ecc_opts[val])) {
+			if (!strcmp(s, nand_ecc_opts[val])) {
 				gpmc_nand_data->ecc_opt = val;
 				break;
 			}
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 6bf9ef4..ce74576 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -23,13 +23,21 @@ enum nand_io {
 };
 
 enum omap_ecc {
-		/* 1-bit ecc: stored at end of spare area */
-	OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
-	OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
-		/* 1-bit ecc: stored at beginning of spare area as romcode */
-	OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
-	OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
-	OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
+	/* 1-bit  ECC calculation by Software, Error detection by Software */
+	OMAP_ECC_HAMMING_CODE_DEFAULT = 0,
+	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_HAMMING_CODE_HW,
+	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
+	/* ECC layout compatible to legacy ROMCODE. */
+	OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH4_CODE_HW,
+	/* 4-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH8_CODE_HW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW
 };
 
 struct gpmc_nand_regs {
-- 
1.8.1



From pekon at ti.com  Sat Jun 22 17:03:46 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 02:33:46 +0530
Subject: [PATCH v3 0/4] mtd:nand:omap2: clean-up of supported ECC schemes
Message-ID: <1371935030-20773-1-git-send-email-pekon@ti.com>

Changes v2 -> v3
- PATCH-1: re-arranged code to remove redundancy, added NAND_BUSWIDTH_AUTO
- PATCH-2: updated nand-ecc-opt DT mapping and Documentation
- PATCH-3: code-cleaning + changes to match PATCH-1
- PATCH-4 <DROPPED> update DT attribute for ti,nand-ecc-opt 
	- received feedback to keep DT mapping independent of linuxism
- PATCH-4:<NEW> : ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt
	- independent patch for AM335x-evm.dts update based on PATCH-2

Changes v1 -> v2
	added 	[PATCH 3/4] and [PATCH 4/4]

Patches in this series:
[PATCH 1/4]: clean-up and optimization for supported ECC schemes.
[PATCH 2/4]: add separate DT options each supported ECC scheme.
[PATCH 3/4]: update BCH4 ECC implementation (using ELM or using lib/bch.h)
[PATCH 4/4]: ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt

After this patch series, omap2-nand driver will supports following ECC schemes:
+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH4_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH4_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
- Selection of OMAP_ECC_BCHx_CODE_HW_DETECTION_SW requires,
	Kconfig: CONFIG_MTD_NAND_ECC_BCH: enables S/W based BCH ECC algorithm.

- Selection of OMAP_ECC_BCHx_CODE_HW requires,
	Kconfig: CONFIG_MTD_NAND_OMAP_BCH: enables ELM H/W module.


Gupta, Pekon (3):
  mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in
    device_probe
  ARM: OMAP2+: cleaned-up DT support of various ECC schemes
  mtd:nand:omap2: updated support for BCH4 ECC scheme

Pekon Gupta (1):
  ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt

 .../devicetree/bindings/mtd/gpmc-nand.txt          |  65 ++-
 arch/arm/boot/dts/am335x-evm.dts                   |   2 +-
 arch/arm/mach-omap2/gpmc.c                         |  14 +-
 drivers/mtd/nand/Kconfig                           |   7 +-
 drivers/mtd/nand/omap2.c                           | 482 ++++++++++-----------
 include/linux/platform_data/elm.h                  |   4 +
 include/linux/platform_data/mtd-nand-omap2.h       |  22 +-
 7 files changed, 307 insertions(+), 289 deletions(-)

-- 
1.8.1



From pekon at ti.com  Sat Jun 22 17:03:50 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 02:33:50 +0530
Subject: [PATCH v3 4/4] ARM: dts: AM33xx: updated default ECC scheme in
 nand-ecc-opt
In-Reply-To: <1371935030-20773-1-git-send-email-pekon@ti.com>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
Message-ID: <1371935030-20773-5-git-send-email-pekon@ti.com>

DT property values for OMAP based gpmc-nand have been updated
to match changes in commit:
	6faf096 ARM: OMAP2+: cleaned-up DT support of various ECC schemes
Refer: Documentation/devicetree/bindings/mtd/gpmc-nand.txt

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 7d2be9c..da64585 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -135,7 +135,7 @@
 			nand at 0,0 {
 				reg = <0 0 0>; /* CS0, offset 0 */
 				nand-bus-width = <8>;
-				ti,nand-ecc-opt = "bch8";
+				ti,nand-ecc-opt = "bch8_code_hw";
 				gpmc,device-nand = "true";
 				gpmc,device-width = <1>;
 				gpmc,sync-clk-ps = <0>;
-- 
1.8.1



From pekon at ti.com  Sat Jun 22 17:03:49 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 02:33:49 +0530
Subject: [PATCH v3 3/4] mtd:nand:omap2: updated support for BCH4 ECC scheme
In-Reply-To: <1371935030-20773-1-git-send-email-pekon@ti.com>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
Message-ID: <1371935030-20773-4-git-send-email-pekon@ti.com>

From: "Gupta, Pekon" <pekon at ti.com>

This patch adds following two flavours of BCH4 ECC scheme in omap2-nand driver
- OMAP_ECC_BCH4_CODE_HW_DETECTION_SW
	- uses GPMC H/W engine for calculating ECC.
	- uses software library (lib/bch.h & nand_bch.h) for error correction.

- OMAP_ECC_BCH4_CODE_HW
	- uses GPMC H/W engine for calculating ECC.
	- uses ELM H/W engine for error correction.

With this patch omap2-nand driver supports following ECC schemes:
+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH4_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH4_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
Important:
- Selection of OMAP_ECC_BCHx_CODE_HW_DETECTION_SW requires,
	Kconfig: CONFIG_MTD_NAND_ECC_BCH: enables S/W based BCH ECC algorithm.

- Selection of OMAP_ECC_BCHx_CODE_HW requires,
	Kconfig: CONFIG_MTD_NAND_OMAP_BCH: enables ELM H/W module.

Signed-off-by: Pekon Gupta <pekon at ti.com>
Tested-by: jean-philippe francois <jp.francois at cynove.com>

---
 .../devicetree/bindings/mtd/gpmc-nand.txt          |  27 +++-
 drivers/mtd/nand/Kconfig                           |   7 +-
 drivers/mtd/nand/omap2.c                           | 166 +++++++++------------
 include/linux/platform_data/mtd-nand-omap2.h       |  10 +-
 4 files changed, 100 insertions(+), 110 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 690070e..b3f23df 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -28,26 +28,43 @@ Optional properties:
 	"hamming_code_sw"		1-bit Hamming ECC
 					- ECC calculation in software
 					- Error detection in software
+					- ECC layout compatible with S/W scheme
 
 	"hamming_code_hw"		1-bit Hamming ECC
 					- ECC calculation in hardware
 					- Error detection in software
+					- ECC layout compatible with S/W scheme
 
 	"hamming_code_hw_romcode"	1-bit Hamming ECC
 					- ECC calculation in hardware
 					- Error detection in software
-					- ECC layout compatible to ROM code
+					- ECC layout compatible with ROM code
 
-	"bch8_hw_code_detection_sw"	8-bit BCH ECC
+	"bch4_code_hw_detection_sw"	4-bit BCH ECC
 					- ECC calculation in hardware
 					- Error detection in software
-					- depends on CONFIG_MTD_NAND_ECC_BCH
+					- ECC layout compatible with S/W scheme
+					* depends on CONFIG_MTD_NAND_ECC_BCH
+
+	"bch4_code_hw"             	4-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in hardware
+					- ECC layout compatible with ROM code
+					* depends on CONFIG_MTD_NAND_OMAP_BCH
+					* requires <elm_id> to be specified
+
+	"bch8_code_hw_detection_sw"	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- ECC layout compatible with S/W scheme
+					* depends on CONFIG_MTD_NAND_ECC_BCH
 
 	"bch8_code_hw"             	8-bit BCH ECC
 					- ECC calculation in hardware
 					- Error detection in hardware
-					- depends on CONFIG_MTD_NAND_OMAP_BCH
-					- requires <elm_id> to be specified
+					- ECC layout compatible with ROM code
+					* depends on CONFIG_MTD_NAND_OMAP_BCH
+					* requires <elm_id> to be specified
 
 
  - elm_id:			Specifies elm device node. This is required to
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a60f6c1..623a707 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -95,16 +95,15 @@ config MTD_NAND_OMAP2
 
 config MTD_NAND_OMAP_BCH
 	depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
-	bool "Enable support for hardware BCH error correction"
+	bool "Support hardware based BCH error correction"
 	default n
 	select BCH
-	select BCH_CONST_PARAMS
 	help
 	 Support for hardware BCH error correction.
 
 choice
-	prompt "BCH error correction capability"
-	depends on MTD_NAND_OMAP_BCH
+	prompt "BCH error correction capability selection (for non-DT kernel)"
+	depends on !OF_MTD && MTD_NAND_OMAP_BCH
 
 config MTD_NAND_OMAP_BCH8
 	bool "8 bits / 512 bytes (recommended)"
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index b525060..be4350f 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -27,6 +27,7 @@
 
 #ifdef CONFIG_MTD_NAND_ECC_BCH
 #include <linux/bch.h>
+#include <linux/mtd/nand_bch.h>
 #endif
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/platform_data/elm.h>
@@ -144,7 +145,6 @@
 #define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
 
 #define BADBLOCK_MARKER_LENGTH		0x2
-#define OMAP_ECC_BCH8_POLYNOMIAL	0x201b
 
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
@@ -185,10 +185,9 @@ struct omap_nand_info {
 		OMAP_NAND_IO_WRITE,	/* write */
 	} iomode;
 	u_char				*buf;
-	int					buf_len;
+	int				buf_len;
 	struct gpmc_nand_regs		reg;
 	/* fields specific for BCHx_HW ECC scheme */
-	struct bch_control              *bch;
 	bool				is_elm_used;
 	struct device			*elm_dev;
 	struct device_node		*of_node;
@@ -1227,58 +1226,6 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
 	return 0;
 }
 
-/**
- * omap3_correct_data_bch - Decode received data and correct errors
- * @mtd: MTD device structure
- * @data: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- */
-static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
-				  u_char *read_ecc, u_char *calc_ecc)
-{
-	int i, count;
-	/* cannot correct more than 8 errors */
-	unsigned int errloc[8];
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-
-	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
-			   errloc);
-	if (count > 0) {
-		/* correct errors */
-		for (i = 0; i < count; i++) {
-			/* correct data only, not ecc bytes */
-			if (errloc[i] < 8*512)
-				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
-			pr_debug("corrected bitflip %u\n", errloc[i]);
-		}
-	} else if (count < 0) {
-		pr_err("ecc unrecoverable error\n");
-	}
-	return count;
-}
-
-/**
- * omap3_free_bch - Release BCH ecc resources
- * @mtd: MTD device structure
- */
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	if (info->bch) {
-		free_bch(info->bch);
-		info->bch = NULL;
-	}
-}
-
-#else
-
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-}
-
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
 
@@ -1730,13 +1677,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
 	info->reg		= pdata->reg;
-	info->bch		= NULL;
 
 	info->nand.options	= NAND_BUSWIDTH_AUTO;
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 	info->of_node		= pdata->of_node;
 #endif
+	info->nand.ecc.priv			= NULL;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
@@ -1933,19 +1880,42 @@ static int omap_nand_probe(struct platform_device *pdev)
 							omap_oobinfo.eccbytes;
 		goto custom_ecc_layout;
 
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC scheme");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 7;
+		info->nand.ecc.strength		= 4;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= nand_bch_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		/* software bch library is used for locating errors */
+		info->nand.ecc.priv		= nand_bch_init(mtd,
+						info->nand.ecc.size,
+						info->nand.ecc.bytes,
+						&info->nand.ecc.layout);
+		if (!info->nand.ecc.priv) {
+			pr_err("unable initialize S/W BCH logic\n");
+			err = -EINVAL;
+			goto out_release_mem_region;
+		}
+		goto generic_ecc_layout;
+#endif
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
-	case OMAP_ECC_BCH8_CODE_HW:
-		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
-		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+	case OMAP_ECC_BCH4_CODE_HW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW ECC scheme");
+		/* check if ELM module is present on SoC */
+		if (is_elm_present(info, ECC_TYPE_BCH4) < 0) {
 			pr_err("ELM module not detected, required for ECC\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
 		info->nand.ecc.mode		= NAND_ECC_HW;
 		info->nand.ecc.size		= 512;
-		/* 14th bit is kept reserved for ROM-code compatibility */
-		info->nand.ecc.bytes		= 13 + 1;
-		info->nand.ecc.strength		= 8;
+		/* 8th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 7 + 1;
+		info->nand.ecc.strength		= 4;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
 		info->nand.ecc.correct		= omap_elm_correct_data;
 		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
@@ -1968,51 +1938,45 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->nand.ecc.bytes		= 13;
 		info->nand.ecc.strength		= 8;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
-		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.correct		= nand_bch_correct_data;
 		info->nand.ecc.calculate	= omap3_calculate_ecc_bch8;
-		/* define custom ECC layout */
-		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
-							(mtd->writesize /
-							info->nand.ecc.size);
-		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
-							omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
 		/* software bch library is used for locating errors */
-		info->bch = init_bch(info->nand.ecc.bytes,
-					info->nand.ecc.strength,
-					OMAP_ECC_BCH8_POLYNOMIAL);
-		if (!info->bch) {
+		info->nand.ecc.priv		= nand_bch_init(mtd,
+						info->nand.ecc.size,
+						info->nand.ecc.bytes,
+						&info->nand.ecc.layout);
+		if (!info->nand.ecc.priv) {
 			pr_err("unable initialize S/W BCH logic\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-		goto custom_ecc_layout;
-
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC\n");
+		goto generic_ecc_layout;
+#endif
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+	case OMAP_ECC_BCH8_CODE_HW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+			pr_err("ELM module not detected, required for ECC\n");
+			err = -EINVAL;
+			goto out_release_mem_region;
+		}
 		info->nand.ecc.mode		= NAND_ECC_HW;
 		info->nand.ecc.size		= 512;
-		info->nand.ecc.bytes		= 7;
-		info->nand.ecc.strength		= 4;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 13 + 1;
+		info->nand.ecc.strength		= 8;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
-		info->nand.ecc.correct		= omap3_correct_data_bch;
-		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		info->nand.ecc.correct		= omap_elm_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
+		info->nand.ecc.read_page	= omap_read_page_bch;
+		info->nand.ecc.write_page	= omap_write_page_bch;
 		/* define custom ECC layout */
 		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
 							(mtd->writesize /
 							info->nand.ecc.size);
-		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+		omap_oobinfo.eccpos[0]		= BADBLOCK_MARKER_LENGTH;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
 							omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
-		/* software bch library is used for locating errors */
-		info->bch = init_bch(info->nand.ecc.bytes,
-					info->nand.ecc.strength,
-					OMAP_ECC_BCH8_POLYNOMIAL);
-		if (!info->bch) {
-			pr_err("unable initialize S/W BCH logic\n");
-			err = -EINVAL;
-			goto out_release_mem_region;
-		}
 		goto custom_ecc_layout;
 #endif
 	default:
@@ -2064,8 +2028,14 @@ out_release_mem_region:
 	if (info->gpmc_irq_fifo > 0)
 		free_irq(info->gpmc_irq_fifo, info);
 	release_mem_region(info->phys_base, info->mem_size);
+
 out_free_info:
-	omap3_free_bch(&info->mtd);
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	if (info->nand.ecc.priv) {
+		nand_bch_free(info->nand.ecc.priv);
+		info->nand.ecc.priv = NULL;
+	}
+#endif
 	kfree(info);
 
 	return err;
@@ -2077,8 +2047,12 @@ static int omap_nand_remove(struct platform_device *pdev)
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	omap3_free_bch(&info->mtd);
-
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	if (info->nand.ecc.priv) {
+		nand_bch_free(info->nand.ecc.priv);
+		info->nand.ecc.priv = NULL;
+	}
+#endif
 	platform_set_drvdata(pdev, NULL);
 	if (info->dma)
 		dma_release_channel(info->dma);
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index ce74576..9fcee61 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -30,14 +30,14 @@ enum omap_ecc {
 	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
 	/* ECC layout compatible to legacy ROMCODE. */
 	OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
-	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
-	OMAP_ECC_BCH4_CODE_HW,
 	/* 4-bit  ECC calculation by GPMC, Error detection by Software */
 	OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
-	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
-	OMAP_ECC_BCH8_CODE_HW,
+	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH4_CODE_HW,
 	/* 8-bit  ECC calculation by GPMC, Error detection by Software */
-	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW
+	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH8_CODE_HW
 };
 
 struct gpmc_nand_regs {
-- 
1.8.1



From balbi at ti.com  Sat Jun 22 17:47:17 2013
From: balbi at ti.com (Felipe Balbi)
Date: Sun, 23 Jun 2013 00:47:17 +0300
Subject: [PATCH v3 1/4] mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC
 configurations in device_probe
In-Reply-To: <1371935030-20773-2-git-send-email-pekon@ti.com>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
 <1371935030-20773-2-git-send-email-pekon@ti.com>
Message-ID: <20130622214717.GA1569@arwen.pp.htv.fi>

On Sun, Jun 23, 2013 at 02:33:47AM +0530, Pekon Gupta wrote:
> From: "Gupta, Pekon" <pekon at ti.com>

Can you fix your From address ? I guess:

git config --global user.name "Pekon Gupta"

should do it, but you'll have to recommit those commits with:

git commit --amend --reset-author

cheers

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130623/3f6fa1f1/attachment-0001.sig>

From pekon at ti.com  Sun Jun 23 13:58:15 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 23:28:15 +0530
Subject: [PATCH v3 0/4] mtd:nand:omap2: clean-up of supported ECC schemes
Message-ID: <1372010299-30141-1-git-send-email-pekon@ti.com>

(with Author Name fixed)
Changes v2 -> v3
- PATCH-1: re-arranged code to remove redundancy, added NAND_BUSWIDTH_AUTO
- PATCH-2: updated nand-ecc-opt DT mapping and Documentation
- PATCH-3: code-cleaning + changes to match PATCH-1
- PATCH-4 <DROPPED> update DT attribute for ti,nand-ecc-opt 
	- received feedback to keep DT mapping independent of linuxism
- PATCH-4:<NEW> : ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt
	- independent patch for AM335x-evm.dts update based on PATCH-2

Changes v1 -> v2
	added 	[PATCH 3/4] and [PATCH 4/4]

Patches in this series:
[PATCH 1/4]: clean-up and optimization for supported ECC schemes.
[PATCH 2/4]: add separate DT options each supported ECC scheme.
[PATCH 3/4]: update BCH4 ECC implementation (using ELM or using lib/bch.h)
[PATCH 4/4]: ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt

After this patch series, omap2-nand driver will supports following ECC schemes:
+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH4_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH4_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
- Selection of OMAP_ECC_BCHx_CODE_HW_DETECTION_SW requires,
	Kconfig: CONFIG_MTD_NAND_ECC_BCH: enables S/W based BCH ECC algorithm.

- Selection of OMAP_ECC_BCHx_CODE_HW requires,
	Kconfig: CONFIG_MTD_NAND_OMAP_BCH: enables ELM H/W module.


Pekon Gupta (4):
  mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in
    device_probe
  ARM: OMAP2+: cleaned-up DT support of various ECC schemes
  mtd:nand:omap2: updated support for BCH4 ECC scheme
  ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt

 .../devicetree/bindings/mtd/gpmc-nand.txt          |  65 ++-
 arch/arm/boot/dts/am335x-evm.dts                   |   2 +-
 arch/arm/mach-omap2/gpmc.c                         |  14 +-
 drivers/mtd/nand/Kconfig                           |   7 +-
 drivers/mtd/nand/omap2.c                           | 482 ++++++++++-----------
 include/linux/platform_data/elm.h                  |   4 +
 include/linux/platform_data/mtd-nand-omap2.h       |  22 +-
 7 files changed, 307 insertions(+), 289 deletions(-)

-- 
1.8.1



From pekon at ti.com  Sun Jun 23 13:58:16 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 23:28:16 +0530
Subject: [PATCH v3 1/4] mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC
 configurations in device_probe
In-Reply-To: <1372010299-30141-1-git-send-email-pekon@ti.com>
References: <1372010299-30141-1-git-send-email-pekon@ti.com>
Message-ID: <1372010299-30141-2-git-send-email-pekon@ti.com>

ECC scheme on NAND devices can be implemented in multiple ways.Some using
Software algorithm, while others using in-build Hardware engines.
omap2-nand driver currently supports following flavours of ECC schemes.

+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_ECC_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_OMAP_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+

This patch
- separates the configurations for various ECC schemes.
- fixes dependency issues based on Kconfig options.
- cleans up redundant code

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 drivers/mtd/nand/omap2.c          | 504 +++++++++++++++++++-------------------
 include/linux/platform_data/elm.h |   4 +
 2 files changed, 252 insertions(+), 256 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 81b80af..b525060 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -25,8 +25,10 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 #include <linux/bch.h>
+#endif
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/platform_data/elm.h>
 #endif
 
@@ -141,6 +143,9 @@
 #define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
 #define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
 
+#define BADBLOCK_MARKER_LENGTH		0x2
+#define OMAP_ECC_BCH8_POLYNOMIAL	0x201b
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
 	0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -182,14 +187,11 @@ struct omap_nand_info {
 	u_char				*buf;
 	int					buf_len;
 	struct gpmc_nand_regs		reg;
-
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-	struct bch_control             *bch;
-	struct nand_ecclayout           ecclayout;
+	/* fields specific for BCHx_HW ECC scheme */
+	struct bch_control              *bch;
 	bool				is_elm_used;
 	struct device			*elm_dev;
 	struct device_node		*of_node;
-#endif
 };
 
 /**
@@ -1058,8 +1060,6 @@ static int omap_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-
 /**
  * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
  * @mtd: MTD device structure
@@ -1141,6 +1141,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
 }
 
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 /**
  * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
  * @mtd: MTD device structure
@@ -1227,6 +1228,62 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
 }
 
 /**
+ * omap3_correct_data_bch - Decode received data and correct errors
+ * @mtd: MTD device structure
+ * @data: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ */
+static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
+				  u_char *read_ecc, u_char *calc_ecc)
+{
+	int i, count;
+	/* cannot correct more than 8 errors */
+	unsigned int errloc[8];
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+						   mtd);
+
+	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
+			   errloc);
+	if (count > 0) {
+		/* correct errors */
+		for (i = 0; i < count; i++) {
+			/* correct data only, not ecc bytes */
+			if (errloc[i] < 8*512)
+				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
+			pr_debug("corrected bitflip %u\n", errloc[i]);
+		}
+	} else if (count < 0) {
+		pr_err("ecc unrecoverable error\n");
+	}
+	return count;
+}
+
+/**
+ * omap3_free_bch - Release BCH ecc resources
+ * @mtd: MTD device structure
+ */
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+						   mtd);
+	if (info->bch) {
+		free_bch(info->bch);
+		info->bch = NULL;
+	}
+}
+
+#else
+
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_BCH */
+
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+/**
  * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
  * @mtd:	MTD device structure
  * @dat:	The pointer to data on which ecc is computed
@@ -1519,38 +1576,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
 }
 
 /**
- * omap3_correct_data_bch - Decode received data and correct errors
- * @mtd: MTD device structure
- * @data: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- */
-static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
-				  u_char *read_ecc, u_char *calc_ecc)
-{
-	int i, count;
-	/* cannot correct more than 8 errors */
-	unsigned int errloc[8];
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-
-	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
-			   errloc);
-	if (count > 0) {
-		/* correct errors */
-		for (i = 0; i < count; i++) {
-			/* correct data only, not ecc bytes */
-			if (errloc[i] < 8*512)
-				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
-			pr_debug("corrected bitflip %u\n", errloc[i]);
-		}
-	} else if (count < 0) {
-		pr_err("ecc unrecoverable error\n");
-	}
-	return count;
-}
-
-/**
  * omap_write_page_bch - BCH ecc based write page function for entire page
  * @mtd:		mtd info structure
  * @chip:		nand chip info structure
@@ -1637,197 +1662,47 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * omap3_free_bch - Release BCH ecc resources
- * @mtd: MTD device structure
- */
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	if (info->bch) {
-		free_bch(info->bch);
-		info->bch = NULL;
-	}
-}
-
-/**
- * omap3_init_bch - Initialize BCH ECC
- * @mtd: MTD device structure
- * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
+ * is_elm_present - checks for presence of ELM module by scanning DT nodes
+ * @omap_nand_info: NAND device structure containing platform data
+ * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
  */
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
+static int is_elm_present(struct omap_nand_info *info, int bch_type)
 {
-	int max_errors;
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-#ifdef CONFIG_MTD_NAND_OMAP_BCH8
-	const int hw_errors = BCH8_MAX_ERROR;
-#else
-	const int hw_errors = BCH4_MAX_ERROR;
-#endif
-	enum bch_ecc bch_type;
 	const __be32 *parp;
 	int lenp;
 	struct device_node *elm_node;
-
-	info->bch = NULL;
-
-	max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
-		BCH8_MAX_ERROR : BCH4_MAX_ERROR;
-	if (max_errors != hw_errors) {
-		pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
-		       max_errors, hw_errors);
-		goto fail;
-	}
-
-	info->nand.ecc.size = 512;
-	info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
-	info->nand.ecc.mode = NAND_ECC_HW;
-	info->nand.ecc.strength = max_errors;
-
-	if (hw_errors == BCH8_MAX_ERROR)
-		bch_type = BCH8_ECC;
-	else
-		bch_type = BCH4_ECC;
+	struct platform_device *pdev;
+	info->is_elm_used = false;
 
 	/* Detect availability of ELM module */
 	parp = of_get_property(info->of_node, "elm_id", &lenp);
 	if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
 		pr_err("Missing elm_id property, fall back to Software BCH\n");
-		info->is_elm_used = false;
 	} else {
-		struct platform_device *pdev;
-
 		elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
 		pdev = of_find_device_by_node(elm_node);
 		info->elm_dev = &pdev->dev;
-
-		if (elm_config(info->elm_dev, bch_type) == 0)
-			info->is_elm_used = true;
-	}
-
-	if (info->is_elm_used && (mtd->writesize <= 4096)) {
-
-		if (hw_errors == BCH8_MAX_ERROR)
-			info->nand.ecc.bytes = BCH8_SIZE;
-		else
-			info->nand.ecc.bytes = BCH4_SIZE;
-
-		info->nand.ecc.correct = omap_elm_correct_data;
-		info->nand.ecc.calculate = omap3_calculate_ecc_bch;
-		info->nand.ecc.read_page = omap_read_page_bch;
-		info->nand.ecc.write_page = omap_write_page_bch;
-	} else {
-		/*
-		 * software bch library is only used to detect and
-		 * locate errors
-		 */
-		info->bch = init_bch(13, max_errors,
-				0x201b /* hw polynomial */);
-		if (!info->bch)
-			goto fail;
-
-		info->nand.ecc.correct = omap3_correct_data_bch;
-
-		/*
-		 * The number of corrected errors in an ecc block that will
-		 * trigger block scrubbing defaults to the ecc strength (4 or 8)
-		 * Set mtd->bitflip_threshold here to define a custom threshold.
-		 */
-
-		if (max_errors == 8) {
-			info->nand.ecc.bytes = 13;
-			info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
-		} else {
-			info->nand.ecc.bytes = 7;
-			info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
-		}
-	}
-
-	pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
-	return 0;
-fail:
-	omap3_free_bch(mtd);
-	return -1;
-}
-
-/**
- * omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
- * @mtd: MTD device structure
- */
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-	int i, steps, offset;
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	struct nand_ecclayout *layout = &info->ecclayout;
-
-	/* build oob layout */
-	steps = mtd->writesize/info->nand.ecc.size;
-	layout->eccbytes = steps*info->nand.ecc.bytes;
-
-	/* do not bother creating special oob layouts for small page devices */
-	if (mtd->oobsize < 64) {
-		pr_err("BCH ecc is not supported on small page devices\n");
-		goto fail;
-	}
-
-	/* reserve 2 bytes for bad block marker */
-	if (layout->eccbytes+2 > mtd->oobsize) {
-		pr_err("no oob layout available for oobsize %d eccbytes %u\n",
-		       mtd->oobsize, layout->eccbytes);
-		goto fail;
+		/* ELM module available, now configure it */
+		elm_config(info->elm_dev, bch_type);
+		info->is_elm_used = true;
+		return 0;
 	}
 
-	/* ECC layout compatible with RBL for BCH8 */
-	if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-		offset = 2;
-	else
-		offset = mtd->oobsize - layout->eccbytes;
-
-	/* put ecc bytes at oob tail */
-	for (i = 0; i < layout->eccbytes; i++)
-		layout->eccpos[i] = offset + i;
-
-	if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-		layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
-	else
-		layout->oobfree[0].offset = 2;
-
-	layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
-	info->nand.ecc.layout = layout;
-
-	if (!(info->nand.options & NAND_BUSWIDTH_16))
-		info->nand.badblock_pattern = &bb_descrip_flashbased;
-	return 0;
-fail:
-	omap3_free_bch(mtd);
-	return -1;
-}
-
-#else
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
-{
-	pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
-	return -1;
-}
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-	return -1;
-}
-static void omap3_free_bch(struct mtd_info *mtd)
-{
+	return -ENODEV;
 }
 #endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info		*info;
 	struct omap_nand_platform_data	*pdata;
+	struct mtd_info			*mtd;
+	struct nand_chip		*chip;
 	int				err;
-	int				i, offset;
-	dma_cap_mask_t mask;
-	unsigned sig;
+	int				i;
+	dma_cap_mask_t			mask;
+	unsigned			sig;
 	struct resource			*res;
 	struct mtd_part_parser_data	ppdata = {};
 
@@ -1846,16 +1721,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
-	info->pdev = pdev;
+	mtd			= &info->mtd;
+	mtd->name		= dev_name(&pdev->dev);
+	mtd->owner		= THIS_MODULE;
+	mtd->priv		= &info->nand;
+	chip			= mtd->priv;
 
+	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
 	info->reg		= pdata->reg;
+	info->bch		= NULL;
 
-	info->mtd.priv		= &info->nand;
-	info->mtd.name		= dev_name(&pdev->dev);
-	info->mtd.owner		= THIS_MODULE;
-
-	info->nand.options	= pdata->devsize;
+	info->nand.options	= NAND_BUSWIDTH_AUTO;
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 	info->of_node		= pdata->of_node;
@@ -1903,6 +1780,31 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->nand.chip_delay = 50;
 	}
 
+	/* scan NAND device conncted to controller */
+	if (nand_scan_ident(mtd, 1, NULL)) {
+		err = -ENXIO;
+		goto out_release_mem_region;
+	}
+	pr_info("%s: detected %s NAND flash\n", DRIVER_NAME,
+			(info->nand.options & NAND_BUSWIDTH_16) ? "x16" : "x8");
+	if ((info->nand.options & NAND_BUSWIDTH_16) !=
+			(pdata->devsize & NAND_BUSWIDTH_16)) {
+		pr_err("%s: but incorrectly configured as %s", DRIVER_NAME,
+			(pdata->devsize & NAND_BUSWIDTH_16) ? "x16" : "x8");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+	/* check for small page devices */
+	if ((mtd->oobsize < 64) &&
+		(pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_DEFAULT) &&
+		(pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_HW)) {
+		pr_err("small page devices are not supported\n");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+	/* populate read & write API based on xfer_type selected */
 	switch (pdata->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		info->nand.read_buf   = omap_read_buf_pref;
@@ -1992,66 +1894,154 @@ static int omap_nand_probe(struct platform_device *pdev)
 		goto out_release_mem_region;
 	}
 
-	/* select the ecc type */
-	if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
-		info->nand.ecc.mode = NAND_ECC_SOFT;
-	else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
-		(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
+	/* populate MTD interface based on ECC scheme */
+	switch (pdata->ecc_opt) {
+	case OMAP_ECC_HAMMING_CODE_DEFAULT:
+		pr_info("using OMAP_ECC_HAMMING_CODE_DEFAULT ECC scheme\n");
+		info->nand.ecc.mode		= NAND_ECC_SOFT;
+		goto generic_ecc_layout;
+
+	case OMAP_ECC_HAMMING_CODE_HW:
+		pr_info("using OMAP_ECC_HAMMING_CODE_HW ECC scheme\n");
+		info->nand.ecc.mode             = NAND_ECC_HW;
 		info->nand.ecc.bytes            = 3;
 		info->nand.ecc.size             = 512;
 		info->nand.ecc.strength         = 1;
 		info->nand.ecc.calculate        = omap_calculate_ecc;
 		info->nand.ecc.hwctl            = omap_enable_hwecc;
 		info->nand.ecc.correct          = omap_correct_data;
+		goto generic_ecc_layout;
+
+	case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+		pr_info("using OMAP_ECC_HAMMING_CODE_HW_ROMCODE ECC scheme\n");
 		info->nand.ecc.mode             = NAND_ECC_HW;
-	} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-		   (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-		err = omap3_init_bch(&info->mtd, pdata->ecc_opt);
-		if (err) {
+		info->nand.ecc.bytes            = 3;
+		info->nand.ecc.size             = 512;
+		info->nand.ecc.strength         = 1;
+		info->nand.ecc.calculate        = omap_calculate_ecc;
+		info->nand.ecc.hwctl            = omap_enable_hwecc;
+		info->nand.ecc.correct          = omap_correct_data;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_oobinfo.eccpos[0]	= BADBLOCK_MARKER_LENGTH;
+		else
+			omap_oobinfo.eccpos[0]	= 1;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
+							omap_oobinfo.eccbytes;
+		goto custom_ecc_layout;
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+	case OMAP_ECC_BCH8_CODE_HW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+			pr_err("ELM module not detected, required for ECC\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-	}
-
-	/* DIP switches on some boards change between 8 and 16 bit
-	 * bus widths for flash.  Try the other width if the first try fails.
-	 */
-	if (nand_scan_ident(&info->mtd, 1, NULL)) {
-		info->nand.options ^= NAND_BUSWIDTH_16;
-		if (nand_scan_ident(&info->mtd, 1, NULL)) {
-			err = -ENXIO;
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 13 + 1;
+		info->nand.ecc.strength		= 8;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap_elm_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
+		info->nand.ecc.read_page	= omap_read_page_bch;
+		info->nand.ecc.write_page	= omap_write_page_bch;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= BADBLOCK_MARKER_LENGTH;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
+							omap_oobinfo.eccbytes;
+		goto custom_ecc_layout;
+#endif
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW ECC\n");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 13;
+		info->nand.ecc.strength		= 8;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch8;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+							omap_oobinfo.eccbytes;
+		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
+		/* software bch library is used for locating errors */
+		info->bch = init_bch(info->nand.ecc.bytes,
+					info->nand.ecc.strength,
+					OMAP_ECC_BCH8_POLYNOMIAL);
+		if (!info->bch) {
+			pr_err("unable initialize S/W BCH logic\n");
+			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-	}
-
-	/* rom code layout */
-	if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
-
-		if (info->nand.options & NAND_BUSWIDTH_16)
-			offset = 2;
-		else {
-			offset = 1;
-			info->nand.badblock_pattern = &bb_descrip_flashbased;
-		}
-		omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16);
-		for (i = 0; i < omap_oobinfo.eccbytes; i++)
-			omap_oobinfo.eccpos[i] = i+offset;
-
-		omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->length = info->mtd.oobsize -
-					(offset + omap_oobinfo.eccbytes);
-
-		info->nand.ecc.layout = &omap_oobinfo;
-	} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-		   (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-		/* build OOB layout for BCH ECC correction */
-		err = omap3_init_bch_tail(&info->mtd);
-		if (err) {
+		goto custom_ecc_layout;
+
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC\n");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 7;
+		info->nand.ecc.strength		= 4;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		/* define custom ECC layout */
+		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
+							(mtd->writesize /
+							info->nand.ecc.size);
+		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+							omap_oobinfo.eccbytes;
+		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
+		/* software bch library is used for locating errors */
+		info->bch = init_bch(info->nand.ecc.bytes,
+					info->nand.ecc.strength,
+					OMAP_ECC_BCH8_POLYNOMIAL);
+		if (!info->bch) {
+			pr_err("unable initialize S/W BCH logic\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
+		goto custom_ecc_layout;
+#endif
+	default:
+		pr_err("selected ECC scheme not supported or not enabled\n");
+		err = -EINVAL;
+		goto out_release_mem_region;
+	}
+
+custom_ecc_layout:
+	/* populate remaining info for custom ecc layout */
+	pr_info("%s: using custom ecc layout\n", DRIVER_NAME);
+	omap_oobinfo.oobfree->length = mtd->oobsize - BADBLOCK_MARKER_LENGTH
+						- omap_oobinfo.eccbytes;
+	if (!(info->nand.options & NAND_BUSWIDTH_16))
+		info->nand.badblock_pattern = &bb_descrip_flashbased;
+	for (i = 1; i < omap_oobinfo.eccbytes; i++)
+		omap_oobinfo.eccpos[i] = omap_oobinfo.eccpos[0] + i;
+
+	/* check if NAND OOBSIZE meets ECC scheme requirement */
+	if (mtd->oobsize < (omap_oobinfo.eccbytes +
+					BADBLOCK_MARKER_LENGTH)) {
+		pr_err("not enough OOB bytes required = %d, available=%d\n",
+		       mtd->oobsize, omap_oobinfo.eccbytes);
+		err = -EINVAL;
+		goto out_release_mem_region;
 	}
+	info->nand.ecc.layout = &omap_oobinfo;
 
+generic_ecc_layout:
 	/* second phase scan */
 	if (nand_scan_tail(&info->mtd)) {
 		err = -ENXIO;
@@ -2075,11 +2065,13 @@ out_release_mem_region:
 		free_irq(info->gpmc_irq_fifo, info);
 	release_mem_region(info->phys_base, info->mem_size);
 out_free_info:
+	omap3_free_bch(&info->mtd);
 	kfree(info);
 
 	return err;
 }
 
+
 static int omap_nand_remove(struct platform_device *pdev)
 {
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h
index bf0a83b..5e36e42 100644
--- a/include/linux/platform_data/elm.h
+++ b/include/linux/platform_data/elm.h
@@ -23,6 +23,10 @@ enum bch_ecc {
 	BCH8_ECC,
 };
 
+#define ECC_TYPE_BCH4                (0x0 << 0)
+#define ECC_TYPE_BCH8                (0x1 << 0)
+#define ECC_TYPE_BCH16               (0x2 << 0)
+
 /* ELM support 8 error syndrome process */
 #define ERROR_VECTOR_MAX		8
 
-- 
1.8.1



From pekon at ti.com  Sun Jun 23 13:58:17 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 23:28:17 +0530
Subject: [PATCH v3 2/4] ARM: OMAP2+: cleaned-up DT support of various ECC
 schemes
In-Reply-To: <1372010299-30141-1-git-send-email-pekon@ti.com>
References: <1372010299-30141-1-git-send-email-pekon@ti.com>
Message-ID: <1372010299-30141-3-git-send-email-pekon@ti.com>

ECC scheme on NAND devices can be implemented in multiple ways.Some using
Software algorithm, while others using in-build Hardware engines.
omap2-nand driver currently supports following flavours of ECC schemes,
selectable via DTB.

+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_ECC_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|(requires CONFIG_MTD_NAND_OMAP_BCH)	|		|		|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+

Selection of some ECC schemes also require enabling following Kconfig options.
This was done to optimize footprint of omap2-nand driver.
-Kconfig:CONFIG_MTD_NAND_ECC_BCH	enables S/W based BCH ECC algorithm
-Kconfig:CONFIG_MTD_NAND_OMAP_BCH	enables H/W based BCH ECC algorithm

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 .../devicetree/bindings/mtd/gpmc-nand.txt          | 44 ++++++++++++++++------
 arch/arm/mach-omap2/gpmc.c                         | 14 ++++---
 include/linux/platform_data/mtd-nand-omap2.h       | 22 +++++++----
 3 files changed, 56 insertions(+), 24 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 6a983c1..690070e 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -17,20 +17,42 @@ Required properties:
 
 Optional properties:
 
- - nand-bus-width: 		Set this numeric value to 16 if the hardware
-				is wired that way. If not specified, a bus
-				width of 8 is assumed.
+ - nand-bus-width: 		Determines data-width of the connected device
+				x16 = "16"
+				x8  = "8" (default)
 
- - ti,nand-ecc-opt:		A string setting the ECC layout to use. One of:
 
-		"sw"		Software method (default)
-		"hw"		Hardware method
-		"hw-romcode"	gpmc hamming mode method & romcode layout
-		"bch4"		4-bit BCH ecc code
-		"bch8"		8-bit BCH ecc code
+ - ti,nand-ecc-opt:		Determines the ECC scheme used by driver.
+				It can be any of the following strings:
+
+	"hamming_code_sw"		1-bit Hamming ECC
+					- ECC calculation in software
+					- Error detection in software
+
+	"hamming_code_hw"		1-bit Hamming ECC
+					- ECC calculation in hardware
+					- Error detection in software
+
+	"hamming_code_hw_romcode"	1-bit Hamming ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- ECC layout compatible to ROM code
+
+	"bch8_hw_code_detection_sw"	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- depends on CONFIG_MTD_NAND_ECC_BCH
+
+	"bch8_code_hw"             	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in hardware
+					- depends on CONFIG_MTD_NAND_OMAP_BCH
+					- requires <elm_id> to be specified
+
+
+ - elm_id:			Specifies elm device node. This is required to
+				support some BCH ECC schemes mentioned above.
 
- - elm_id:	Specifies elm device node. This is required to support BCH
- 		error correction using ELM module.
 
 For inline partiton table parsing (optional):
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 6c4da12..ae8bb70 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1338,11 +1338,13 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 #ifdef CONFIG_MTD_NAND
 
 static const char * const nand_ecc_opts[] = {
-	[OMAP_ECC_HAMMING_CODE_DEFAULT]		= "sw",
-	[OMAP_ECC_HAMMING_CODE_HW]		= "hw",
-	[OMAP_ECC_HAMMING_CODE_HW_ROMCODE]	= "hw-romcode",
-	[OMAP_ECC_BCH4_CODE_HW]			= "bch4",
-	[OMAP_ECC_BCH8_CODE_HW]			= "bch8",
+	[OMAP_ECC_HAMMING_CODE_DEFAULT]		= "hamming_code_sw",
+	[OMAP_ECC_HAMMING_CODE_HW]		= "hamming_code_hw",
+	[OMAP_ECC_HAMMING_CODE_HW_ROMCODE]	= "hamming_code_hw_romcode",
+	[OMAP_ECC_BCH4_CODE_HW]			= "bch4_code_hw",
+	[OMAP_ECC_BCH4_CODE_HW_DETECTION_SW]	= "bch4_code_hw_detection_sw",
+	[OMAP_ECC_BCH8_CODE_HW]			= "bch8_code_hw",
+	[OMAP_ECC_BCH8_CODE_HW_DETECTION_SW]	= "bch8_code_hw_detection_sw"
 };
 
 static int gpmc_probe_nand_child(struct platform_device *pdev,
@@ -1369,7 +1371,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
 
 	if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
 		for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
-			if (!strcasecmp(s, nand_ecc_opts[val])) {
+			if (!strcmp(s, nand_ecc_opts[val])) {
 				gpmc_nand_data->ecc_opt = val;
 				break;
 			}
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 6bf9ef4..ce74576 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -23,13 +23,21 @@ enum nand_io {
 };
 
 enum omap_ecc {
-		/* 1-bit ecc: stored at end of spare area */
-	OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
-	OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
-		/* 1-bit ecc: stored at beginning of spare area as romcode */
-	OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
-	OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
-	OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
+	/* 1-bit  ECC calculation by Software, Error detection by Software */
+	OMAP_ECC_HAMMING_CODE_DEFAULT = 0,
+	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_HAMMING_CODE_HW,
+	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
+	/* ECC layout compatible to legacy ROMCODE. */
+	OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH4_CODE_HW,
+	/* 4-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH8_CODE_HW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by Software */
+	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW
 };
 
 struct gpmc_nand_regs {
-- 
1.8.1



From pekon at ti.com  Sun Jun 23 13:58:18 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 23:28:18 +0530
Subject: [PATCH v3 3/4] mtd:nand:omap2: updated support for BCH4 ECC scheme
In-Reply-To: <1372010299-30141-1-git-send-email-pekon@ti.com>
References: <1372010299-30141-1-git-send-email-pekon@ti.com>
Message-ID: <1372010299-30141-4-git-send-email-pekon@ti.com>

This patch adds following two flavours of BCH4 ECC scheme in omap2-nand driver
- OMAP_ECC_BCH4_CODE_HW_DETECTION_SW
	- uses GPMC H/W engine for calculating ECC.
	- uses software library (lib/bch.h & nand_bch.h) for error correction.

- OMAP_ECC_BCH4_CODE_HW
	- uses GPMC H/W engine for calculating ECC.
	- uses ELM H/W engine for error correction.

With this patch omap2-nand driver supports following ECC schemes:
+---------------------------------------+---------------+---------------+
| ECC scheme				|ECC calculation|Error detection|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W		|
|OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W		|
|OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W		|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH4_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH4_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
|OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W (lib/bch.h)|
|OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)	|
+---------------------------------------+---------------+---------------+
Important:
- Selection of OMAP_ECC_BCHx_CODE_HW_DETECTION_SW requires,
	Kconfig: CONFIG_MTD_NAND_ECC_BCH: enables S/W based BCH ECC algorithm.

- Selection of OMAP_ECC_BCHx_CODE_HW requires,
	Kconfig: CONFIG_MTD_NAND_OMAP_BCH: enables ELM H/W module.

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 .../devicetree/bindings/mtd/gpmc-nand.txt          |  27 +++-
 drivers/mtd/nand/Kconfig                           |   7 +-
 drivers/mtd/nand/omap2.c                           | 166 +++++++++------------
 include/linux/platform_data/mtd-nand-omap2.h       |  10 +-
 4 files changed, 100 insertions(+), 110 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index 690070e..b3f23df 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -28,26 +28,43 @@ Optional properties:
 	"hamming_code_sw"		1-bit Hamming ECC
 					- ECC calculation in software
 					- Error detection in software
+					- ECC layout compatible with S/W scheme
 
 	"hamming_code_hw"		1-bit Hamming ECC
 					- ECC calculation in hardware
 					- Error detection in software
+					- ECC layout compatible with S/W scheme
 
 	"hamming_code_hw_romcode"	1-bit Hamming ECC
 					- ECC calculation in hardware
 					- Error detection in software
-					- ECC layout compatible to ROM code
+					- ECC layout compatible with ROM code
 
-	"bch8_hw_code_detection_sw"	8-bit BCH ECC
+	"bch4_code_hw_detection_sw"	4-bit BCH ECC
 					- ECC calculation in hardware
 					- Error detection in software
-					- depends on CONFIG_MTD_NAND_ECC_BCH
+					- ECC layout compatible with S/W scheme
+					* depends on CONFIG_MTD_NAND_ECC_BCH
+
+	"bch4_code_hw"             	4-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in hardware
+					- ECC layout compatible with ROM code
+					* depends on CONFIG_MTD_NAND_OMAP_BCH
+					* requires <elm_id> to be specified
+
+	"bch8_code_hw_detection_sw"	8-bit BCH ECC
+					- ECC calculation in hardware
+					- Error detection in software
+					- ECC layout compatible with S/W scheme
+					* depends on CONFIG_MTD_NAND_ECC_BCH
 
 	"bch8_code_hw"             	8-bit BCH ECC
 					- ECC calculation in hardware
 					- Error detection in hardware
-					- depends on CONFIG_MTD_NAND_OMAP_BCH
-					- requires <elm_id> to be specified
+					- ECC layout compatible with ROM code
+					* depends on CONFIG_MTD_NAND_OMAP_BCH
+					* requires <elm_id> to be specified
 
 
  - elm_id:			Specifies elm device node. This is required to
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a60f6c1..623a707 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -95,16 +95,15 @@ config MTD_NAND_OMAP2
 
 config MTD_NAND_OMAP_BCH
 	depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
-	bool "Enable support for hardware BCH error correction"
+	bool "Support hardware based BCH error correction"
 	default n
 	select BCH
-	select BCH_CONST_PARAMS
 	help
 	 Support for hardware BCH error correction.
 
 choice
-	prompt "BCH error correction capability"
-	depends on MTD_NAND_OMAP_BCH
+	prompt "BCH error correction capability selection (for non-DT kernel)"
+	depends on !OF_MTD && MTD_NAND_OMAP_BCH
 
 config MTD_NAND_OMAP_BCH8
 	bool "8 bits / 512 bytes (recommended)"
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index b525060..be4350f 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -27,6 +27,7 @@
 
 #ifdef CONFIG_MTD_NAND_ECC_BCH
 #include <linux/bch.h>
+#include <linux/mtd/nand_bch.h>
 #endif
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/platform_data/elm.h>
@@ -144,7 +145,6 @@
 #define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
 
 #define BADBLOCK_MARKER_LENGTH		0x2
-#define OMAP_ECC_BCH8_POLYNOMIAL	0x201b
 
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
@@ -185,10 +185,9 @@ struct omap_nand_info {
 		OMAP_NAND_IO_WRITE,	/* write */
 	} iomode;
 	u_char				*buf;
-	int					buf_len;
+	int				buf_len;
 	struct gpmc_nand_regs		reg;
 	/* fields specific for BCHx_HW ECC scheme */
-	struct bch_control              *bch;
 	bool				is_elm_used;
 	struct device			*elm_dev;
 	struct device_node		*of_node;
@@ -1227,58 +1226,6 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
 	return 0;
 }
 
-/**
- * omap3_correct_data_bch - Decode received data and correct errors
- * @mtd: MTD device structure
- * @data: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- */
-static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
-				  u_char *read_ecc, u_char *calc_ecc)
-{
-	int i, count;
-	/* cannot correct more than 8 errors */
-	unsigned int errloc[8];
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-
-	count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
-			   errloc);
-	if (count > 0) {
-		/* correct errors */
-		for (i = 0; i < count; i++) {
-			/* correct data only, not ecc bytes */
-			if (errloc[i] < 8*512)
-				data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
-			pr_debug("corrected bitflip %u\n", errloc[i]);
-		}
-	} else if (count < 0) {
-		pr_err("ecc unrecoverable error\n");
-	}
-	return count;
-}
-
-/**
- * omap3_free_bch - Release BCH ecc resources
- * @mtd: MTD device structure
- */
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-						   mtd);
-	if (info->bch) {
-		free_bch(info->bch);
-		info->bch = NULL;
-	}
-}
-
-#else
-
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-}
-
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
 
@@ -1730,13 +1677,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
 	info->reg		= pdata->reg;
-	info->bch		= NULL;
 
 	info->nand.options	= NAND_BUSWIDTH_AUTO;
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 	info->of_node		= pdata->of_node;
 #endif
+	info->nand.ecc.priv			= NULL;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
@@ -1933,19 +1880,42 @@ static int omap_nand_probe(struct platform_device *pdev)
 							omap_oobinfo.eccbytes;
 		goto custom_ecc_layout;
 
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC scheme");
+		info->nand.ecc.mode		= NAND_ECC_HW;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.bytes		= 7;
+		info->nand.ecc.strength		= 4;
+		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
+		info->nand.ecc.correct		= nand_bch_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		/* software bch library is used for locating errors */
+		info->nand.ecc.priv		= nand_bch_init(mtd,
+						info->nand.ecc.size,
+						info->nand.ecc.bytes,
+						&info->nand.ecc.layout);
+		if (!info->nand.ecc.priv) {
+			pr_err("unable initialize S/W BCH logic\n");
+			err = -EINVAL;
+			goto out_release_mem_region;
+		}
+		goto generic_ecc_layout;
+#endif
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
-	case OMAP_ECC_BCH8_CODE_HW:
-		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
-		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+	case OMAP_ECC_BCH4_CODE_HW:
+		pr_info("using OMAP_ECC_BCH4_CODE_HW ECC scheme");
+		/* check if ELM module is present on SoC */
+		if (is_elm_present(info, ECC_TYPE_BCH4) < 0) {
 			pr_err("ELM module not detected, required for ECC\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
 		info->nand.ecc.mode		= NAND_ECC_HW;
 		info->nand.ecc.size		= 512;
-		/* 14th bit is kept reserved for ROM-code compatibility */
-		info->nand.ecc.bytes		= 13 + 1;
-		info->nand.ecc.strength		= 8;
+		/* 8th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 7 + 1;
+		info->nand.ecc.strength		= 4;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
 		info->nand.ecc.correct		= omap_elm_correct_data;
 		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
@@ -1968,51 +1938,45 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->nand.ecc.bytes		= 13;
 		info->nand.ecc.strength		= 8;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
-		info->nand.ecc.correct		= omap3_correct_data_bch;
+		info->nand.ecc.correct		= nand_bch_correct_data;
 		info->nand.ecc.calculate	= omap3_calculate_ecc_bch8;
-		/* define custom ECC layout */
-		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
-							(mtd->writesize /
-							info->nand.ecc.size);
-		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
-							omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
 		/* software bch library is used for locating errors */
-		info->bch = init_bch(info->nand.ecc.bytes,
-					info->nand.ecc.strength,
-					OMAP_ECC_BCH8_POLYNOMIAL);
-		if (!info->bch) {
+		info->nand.ecc.priv		= nand_bch_init(mtd,
+						info->nand.ecc.size,
+						info->nand.ecc.bytes,
+						&info->nand.ecc.layout);
+		if (!info->nand.ecc.priv) {
 			pr_err("unable initialize S/W BCH logic\n");
 			err = -EINVAL;
 			goto out_release_mem_region;
 		}
-		goto custom_ecc_layout;
-
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-		pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC\n");
+		goto generic_ecc_layout;
+#endif
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+	case OMAP_ECC_BCH8_CODE_HW:
+		pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+		if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+			pr_err("ELM module not detected, required for ECC\n");
+			err = -EINVAL;
+			goto out_release_mem_region;
+		}
 		info->nand.ecc.mode		= NAND_ECC_HW;
 		info->nand.ecc.size		= 512;
-		info->nand.ecc.bytes		= 7;
-		info->nand.ecc.strength		= 4;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		info->nand.ecc.bytes		= 13 + 1;
+		info->nand.ecc.strength		= 8;
 		info->nand.ecc.hwctl		= omap3_enable_hwecc_bch;
-		info->nand.ecc.correct		= omap3_correct_data_bch;
-		info->nand.ecc.calculate	= omap3_calculate_ecc_bch4;
+		info->nand.ecc.correct		= omap_elm_correct_data;
+		info->nand.ecc.calculate	= omap3_calculate_ecc_bch;
+		info->nand.ecc.read_page	= omap_read_page_bch;
+		info->nand.ecc.write_page	= omap_write_page_bch;
 		/* define custom ECC layout */
 		omap_oobinfo.eccbytes		= info->nand.ecc.bytes *
 							(mtd->writesize /
 							info->nand.ecc.size);
-		omap_oobinfo.eccpos[0]		= info->mtd.oobsize -
+		omap_oobinfo.eccpos[0]		= BADBLOCK_MARKER_LENGTH;
+		omap_oobinfo.oobfree->offset	= omap_oobinfo.eccpos[0] +
 							omap_oobinfo.eccbytes;
-		omap_oobinfo.oobfree->offset	= BADBLOCK_MARKER_LENGTH;
-		/* software bch library is used for locating errors */
-		info->bch = init_bch(info->nand.ecc.bytes,
-					info->nand.ecc.strength,
-					OMAP_ECC_BCH8_POLYNOMIAL);
-		if (!info->bch) {
-			pr_err("unable initialize S/W BCH logic\n");
-			err = -EINVAL;
-			goto out_release_mem_region;
-		}
 		goto custom_ecc_layout;
 #endif
 	default:
@@ -2064,8 +2028,14 @@ out_release_mem_region:
 	if (info->gpmc_irq_fifo > 0)
 		free_irq(info->gpmc_irq_fifo, info);
 	release_mem_region(info->phys_base, info->mem_size);
+
 out_free_info:
-	omap3_free_bch(&info->mtd);
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	if (info->nand.ecc.priv) {
+		nand_bch_free(info->nand.ecc.priv);
+		info->nand.ecc.priv = NULL;
+	}
+#endif
 	kfree(info);
 
 	return err;
@@ -2077,8 +2047,12 @@ static int omap_nand_remove(struct platform_device *pdev)
 	struct mtd_info *mtd = platform_get_drvdata(pdev);
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	omap3_free_bch(&info->mtd);
-
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+	if (info->nand.ecc.priv) {
+		nand_bch_free(info->nand.ecc.priv);
+		info->nand.ecc.priv = NULL;
+	}
+#endif
 	platform_set_drvdata(pdev, NULL);
 	if (info->dma)
 		dma_release_channel(info->dma);
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index ce74576..9fcee61 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -30,14 +30,14 @@ enum omap_ecc {
 	/* 1-bit  ECC calculation by GPMC, Error detection by Software */
 	/* ECC layout compatible to legacy ROMCODE. */
 	OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
-	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
-	OMAP_ECC_BCH4_CODE_HW,
 	/* 4-bit  ECC calculation by GPMC, Error detection by Software */
 	OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
-	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
-	OMAP_ECC_BCH8_CODE_HW,
+	/* 4-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH4_CODE_HW,
 	/* 8-bit  ECC calculation by GPMC, Error detection by Software */
-	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW
+	OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
+	/* 8-bit  ECC calculation by GPMC, Error detection by ELM */
+	OMAP_ECC_BCH8_CODE_HW
 };
 
 struct gpmc_nand_regs {
-- 
1.8.1



From pekon at ti.com  Sun Jun 23 13:58:19 2013
From: pekon at ti.com (Pekon Gupta)
Date: Sun, 23 Jun 2013 23:28:19 +0530
Subject: [PATCH v3 4/4] ARM: dts: AM33xx: updated default ECC scheme in
 nand-ecc-opt
In-Reply-To: <1372010299-30141-1-git-send-email-pekon@ti.com>
References: <1372010299-30141-1-git-send-email-pekon@ti.com>
Message-ID: <1372010299-30141-5-git-send-email-pekon@ti.com>

DT property values for OMAP based gpmc-nand have been updated
to match changes in commit:
	6faf096 ARM: OMAP2+: cleaned-up DT support of various ECC schemes
Refer: Documentation/devicetree/bindings/mtd/gpmc-nand.txt

Signed-off-by: Pekon Gupta <pekon at ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 7d2be9c..da64585 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -135,7 +135,7 @@
 			nand at 0,0 {
 				reg = <0 0 0>; /* CS0, offset 0 */
 				nand-bus-width = <8>;
-				ti,nand-ecc-opt = "bch8";
+				ti,nand-ecc-opt = "bch8_code_hw";
 				gpmc,device-nand = "true";
 				gpmc,device-width = <1>;
 				gpmc,sync-clk-ps = <0>;
-- 
1.8.1



From pekon at ti.com  Sun Jun 23 14:06:51 2013
From: pekon at ti.com (Gupta, Pekon)
Date: Sun, 23 Jun 2013 18:06:51 +0000
Subject: [PATCH v3 1/4] mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC
 configurations in device_probe
In-Reply-To: <20130622214717.GA1569@arwen.pp.htv.fi>
References: <1371935030-20773-1-git-send-email-pekon@ti.com>
 <1371935030-20773-2-git-send-email-pekon@ti.com>,
 <20130622214717.GA1569@arwen.pp.htv.fi>
Message-ID: <20980858CB6D3A4BAE95CA194937D5E73E9DF3A8@DBDE04.ent.ti.com>

>> From: "Gupta, Pekon" <pekon at ti.com>

> Can you fix your From address ? I guess:
> git config --global user.name "Pekon Gupta"
> should do it, but you'll have to recommit those commits with:
> git commit --amend --reset-author
[Pekon]: Thanks for pointing it out. I had missed this.
I updated my global config recently, But as this patch series was 
ported from my older branch, so older 'from' string continued.
Fixed now and re-sent.

with regards, pekon

From mkl at pengutronix.de  Mon Jun 24 08:13:13 2013
From: mkl at pengutronix.de (Marc Kleine-Budde)
Date: Mon, 24 Jun 2013 14:13:13 +0200
Subject: xattr patches from feb?
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FCA20D3@post.tritech.se>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FCA20D3@post.tritech.se>
Message-ID: <51C837D9.5060007@pengutronix.de>

On 06/24/2013 01:15 PM, Mats K?rrman wrote:
> Sorry for contacting you directly.

I've added linux-mtd on Cc, maybe there are more people interested in
the patches.

> I have been running integck on UBIFS and found some issues with
> corrupt xattr nodes. I found your post on the linux-mtd mailing list
> but nothing seem to have happened since February.

Yes, unfortunately.

> What has happened since? Were the patches rejected or just ignored? 
> Do you still believe in them?

Nothing happened, our $CUSTOMER shifted priorities. There is a locking
issue with the patches. Which might be a false positive by the lockdep.

I'll send you my current patches as PM, if someone else is interested,
contact me.

regards,
Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130624/e88ccda9/attachment.sig>

From computersforpeace at gmail.com  Mon Jun 24 18:12:44 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Mon, 24 Jun 2013 15:12:44 -0700
Subject: CFC - RW - power-donw ?
In-Reply-To: <1531E53627F1F749B4FE809BF2A4EB67043D97FA@wetmex10>
References: <1531E53627F1F749B4FE809BF2A4EB67043D97FA@wetmex10>
Message-ID: <CAN8TOE8m6VVDuNZwXqa7Rn9pBXoTXci_iyWN4nX-+S3cj422ew@mail.gmail.com>

Hi Noel,

On Wed, Jun 19, 2013 at 11:55 PM, Vellemans, Noel
<Noel.Vellemans at visionbms.com> wrote:
> Hi all,
>
> I've a question regarding a PC that needs to boot from CFC (Compact
> Flash card), hope this is the correct place to ask.
>
> I would need a PC to boot from a CFC-card that has R/W enabled.
>
> At this time I have been testing it with EXT2/EXT3 but when POWERING
> down abruptly it seems that the CFC-ext2/ext3 file system gets
> corrupted, finally resulting in a NON bootable system.

That is somewhat expected. The FTLs for cards like Compact Flash are
not documented and are likely unsafe w.r.t. power cuts.

> At this time I have partitioned the CFC into 2 partitions 1-FAT16 (to
> store the kernel) and 1-ext2/ext3 partition that has the root-file
> system.
>
> What would be the correct file-system (and/or mount /build options) to
> put on a CFC ... so that it is able to survive abrupt-power downs ?
>
> Or is the somewhere a guide (URL) that explains me some more stuff
> regarding this.

The Linux MTD website has some information that is somewhat related,
regarding FTL (Flash Translation Layers) and MTDs. Note that CF cards
are not MTDs but are block devices with a simple built-in hardware
FTL. With that in mind, you might read:

http://www.linux-mtd.infradead.org/faq/general.html#L_mtd_what
http://www.linux-mtd.infradead.org/faq/general.html#L_mtd_vs_hdd
http://www.linux-mtd.infradead.org/faq/jffs2.html#L_hdd_jffs2
http://www.linux-mtd.infradead.org/faq/general.html#L_ext2_mtd

I don't have much personal experience with Compact Flash, but my bet
is that you are running into the perils of relying on cheap
proprietary hardware FTL.

And Google will tell you:

https://groups.google.com/forum/#!topic/comp.os.linux.embedded/0DYdL-PUZVY

The advice there seems reasonable and in line with my knowledge: that
CF cards are inherently prone to power-cut data loss.

Brian


From jg1.han at samsung.com  Mon Jun 24 21:19:13 2013
From: jg1.han at samsung.com (Jingoo Han)
Date: Tue, 25 Jun 2013 10:19:13 +0900
Subject: [PATCH 01/26] mtd: devices: spear_smi: remove unnecessary
 platform_set_drvdata()
In-Reply-To: <004501ce4aeb$bc1006e0$343014a0$@samsung.com>
References: <004501ce4aeb$bc1006e0$343014a0$@samsung.com>
Message-ID: <000701ce7142$008d17f0$01a747d0$@samsung.com>

On Tuesday, May 07, 2013 3:26 PM, Jingoo Han wrote:
> 
> The driver core clears the driver data to NULL after device_release
> or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d
> (device-core: Ensure drvdata = NULL when no driver is bound).
> Thus, it is not needed to manually clear the device driver data to NULL.
> 
> Signed-off-by: Jingoo Han <jg1.han at samsung.com>

Hi Artem Bityutskiy,

I will squash everything down into one patch with the ACKs,
and send it again.

Best regards,
Jingoo Han


> ---
>  drivers/mtd/devices/spear_smi.c |    5 +----
>  1 files changed, 1 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
> index 8a82b8b..e290ef8 100644
> --- a/drivers/mtd/devices/spear_smi.c
> +++ b/drivers/mtd/devices/spear_smi.c
> @@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
>  		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
>  		if (ret) {
>  			dev_err(&dev->pdev->dev, "bank setup failed\n");
> -			goto err_bank_setup;
> +			goto err_irq;
>  		}
>  	}
> 
>  	return 0;
> 
> -err_bank_setup:
> -	platform_set_drvdata(pdev, NULL);
>  err_irq:
>  	clk_disable_unprepare(dev->clk);
>  err:
> @@ -1040,7 +1038,6 @@ static int spear_smi_remove(struct platform_device *pdev)
>  	}
> 
>  	clk_disable_unprepare(dev->clk);
> -	platform_set_drvdata(pdev, NULL);
> 
>  	return 0;
>  }
> --
> 1.7.2.5




From jg1.han at samsung.com  Mon Jun 24 21:34:09 2013
From: jg1.han at samsung.com (Jingoo Han)
Date: Tue, 25 Jun 2013 10:34:09 +0900
Subject: [PATCH V2] mtd: remove unnecessary platform_set_drvdata()
Message-ID: <000b01ce7144$16df2280$449d6780$@samsung.com>

The driver core clears the driver data to NULL after device_release
or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d
(device-core: Ensure drvdata = NULL when no driver is bound).
Thus, it is not needed to manually clear the device driver data to NULL.

Signed-off-by: Jingoo Han <jg1.han at samsung.com>
Acked-by: Marc Kleine-Budde <mkl at blackshift.org>
Acked-by: Shawn Guo <shawn.guo at linaro.org>
Acked-by: Roland Stigge <stigge at antcom.de>
Acked-by: Josh Wu <josh.wu at atmel.com>
Acked-by: Mike Dunn <mikedunn at newsguy.com>
Acked-by: Viresh Kumar <viresh.kumar at linaro.org>
Acked-by: Pekon Gupta <pekon at ti.com>
Tested-by: Roland Stigge <stigge at antcom.de>
---
 drivers/mtd/devices/elm.c              |    1 -
 drivers/mtd/devices/spear_smi.c        |    5 +----
 drivers/mtd/maps/ixp4xx.c              |    2 --
 drivers/mtd/maps/latch-addr-flash.c    |    1 -
 drivers/mtd/maps/physmap.c             |    1 -
 drivers/mtd/maps/plat-ram.c            |    2 --
 drivers/mtd/maps/pxa2xx-flash.c        |    2 --
 drivers/mtd/maps/rbtx4939-flash.c      |    1 -
 drivers/mtd/maps/sa1100-flash.c        |    1 -
 drivers/mtd/nand/ams-delta.c           |    1 -
 drivers/mtd/nand/atmel_nand.c          |    1 -
 drivers/mtd/nand/bf5xx_nand.c          |    3 ---
 drivers/mtd/nand/docg4.c               |    2 --
 drivers/mtd/nand/fsmc_nand.c           |    2 --
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c |    2 --
 drivers/mtd/nand/jz4740_nand.c         |    2 --
 drivers/mtd/nand/lpc32xx_mlc.c         |    2 --
 drivers/mtd/nand/lpc32xx_slc.c         |    2 --
 drivers/mtd/nand/mxc_nand.c            |    2 --
 drivers/mtd/nand/nuc900_nand.c         |    2 --
 drivers/mtd/nand/omap2.c               |    1 -
 drivers/mtd/nand/orion_nand.c          |    1 -
 drivers/mtd/nand/plat_nand.c           |    1 -
 drivers/mtd/nand/pxa3xx_nand.c         |    1 -
 drivers/mtd/nand/s3c2410.c             |    2 --
 drivers/mtd/nand/sharpsl.c             |    3 ---
 drivers/mtd/nand/txx9ndfmc.c           |    1 -
 drivers/mtd/onenand/generic.c          |    2 --
 drivers/mtd/onenand/omap2.c            |    1 -
 drivers/mtd/onenand/samsung.c          |    1 -
 30 files changed, 1 insertion(+), 50 deletions(-)

diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
index fc8ad9f..4fab47a 100644
--- a/drivers/mtd/devices/elm.c
+++ b/drivers/mtd/devices/elm.c
@@ -381,7 +381,6 @@ static int elm_remove(struct platform_device *pdev)
 {
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
 
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
index 0e1c22e..092bb68 100644
--- a/drivers/mtd/devices/spear_smi.c
+++ b/drivers/mtd/devices/spear_smi.c
@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
 		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
 		if (ret) {
 			dev_err(&dev->pdev->dev, "bank setup failed\n");
-			goto err_bank_setup;
+			goto err_irq;
 		}
 	}
 
 	return 0;
 
-err_bank_setup:
-	platform_set_drvdata(pdev, NULL);
 err_irq:
 	clk_disable_unprepare(dev->clk);
 err:
@@ -1040,7 +1038,6 @@ static int spear_smi_remove(struct platform_device *pdev)
 	}
 
 	clk_disable_unprepare(dev->clk);
-	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
index 52b3410..09c542b 100644
--- a/drivers/mtd/maps/ixp4xx.c
+++ b/drivers/mtd/maps/ixp4xx.c
@@ -155,8 +155,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
 	struct flash_platform_data *plat = dev->dev.platform_data;
 	struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 
-	platform_set_drvdata(dev, NULL);
-
 	if(!info)
 		return 0;
 
diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c
index ab0fead..675ccb8 100644
--- a/drivers/mtd/maps/latch-addr-flash.c
+++ b/drivers/mtd/maps/latch-addr-flash.c
@@ -102,7 +102,6 @@ static int latch_addr_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	if (info == NULL)
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 	latch_addr_data = dev->dev.platform_data;
 
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index e7a592c..9eb7ead9 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -40,7 +40,6 @@ static int physmap_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	if (info == NULL)
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 	physmap_data = dev->dev.platform_data;
 
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 71fdda2..b0b85eb 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev)
 {
 	struct platram_info *info = to_platram_info(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	dev_dbg(&pdev->dev, "removing device\n");
 
 	if (info == NULL)
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index acb1dbc..22c55cb 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
 {
 	struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
-	platform_set_drvdata(dev, NULL);
-
 	mtd_device_unregister(info->mtd);
 
 	map_destroy(info->mtd);
diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c
index ac02fbf..ab4ec55 100644
--- a/drivers/mtd/maps/rbtx4939-flash.c
+++ b/drivers/mtd/maps/rbtx4939-flash.c
@@ -34,7 +34,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	if (!info)
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 	if (info->mtd) {
 		struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 29e3dca..9e70f8e 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -279,7 +279,6 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 	struct sa_info *info = platform_get_drvdata(pdev);
 	struct flash_platform_data *plat = pdev->dev.platform_data;
 
-	platform_set_drvdata(pdev, NULL);
 	sa1100_destroy(info, plat);
 
 	return 0;
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index f1d71cd..8611eb4 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev)
  out_mtd:
 	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
 out_gpio:
-	platform_set_drvdata(pdev, NULL);
 	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
 	iounmap(io_base);
 out_free:
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2d23d29..36c52f5 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1665,7 +1665,6 @@ err_hw_ecc:
 err_scan_ident:
 err_no_card:
 	atmel_nand_disable(host);
-	platform_set_drvdata(pdev, NULL);
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 err_ecc_ioremap:
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 776df36..809a63c 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 {
 	struct bf5xx_nand_info *info = to_nand_info(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	/* first thing we need to do is release all our mtds
 	 * and their partitions, then go through freeing the
 	 * resources used
@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 out_err_nand_scan:
 	bf5xx_nand_dma_remove(info);
 out_err_hw_init:
-	platform_set_drvdata(pdev, NULL);
 	kfree(info);
 out_err_kzalloc:
 	peripheral_free_list(bfin_nfc_pin_req);
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index fa25e7a..dc86d4a 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -1368,7 +1368,6 @@ static int __init probe_docg4(struct platform_device *pdev)
 		struct nand_chip *nand = mtd->priv;
 		struct docg4_priv *doc = nand->priv;
 		nand_release(mtd); /* deletes partitions and mtd devices */
-		platform_set_drvdata(pdev, NULL);
 		free_bch(doc->bch);
 		kfree(mtd);
 	}
@@ -1380,7 +1379,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 {
 	struct docg4_priv *doc = platform_get_drvdata(pdev);
 	nand_release(doc->mtd);
-	platform_set_drvdata(pdev, NULL);
 	free_bch(doc->bch);
 	kfree(doc->mtd);
 	iounmap(doc->virtadr);
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 0378386..2a3b1b9 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -1192,8 +1192,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 {
 	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (host) {
 		nand_release(&host->mtd);
 
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 25ecfa1..7869210 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1633,7 +1633,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
 exit_nfc_init:
 	release_resources(this);
 exit_acquire_resources:
-	platform_set_drvdata(pdev, NULL);
 	dev_err(this->dev, "driver registration failed: %d\n", ret);
 	kfree(this);
 
@@ -1646,7 +1645,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 
 	gpmi_nfc_exit(this);
 	release_resources(this);
-	platform_set_drvdata(pdev, NULL);
 	kfree(this);
 	return 0;
 }
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index b76460e..698a4d1 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -538,7 +538,6 @@ err_unclaim_banks:
 err_gpio_busy:
 	if (pdata && gpio_is_valid(pdata->busy_gpio))
 		gpio_free(pdata->busy_gpio);
-	platform_set_drvdata(pdev, NULL);
 err_iounmap_mmio:
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 
-	platform_set_drvdata(pdev, NULL);
 	kfree(nand);
 
 	return 0;
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index fd1df5e..74a469b 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -828,7 +828,6 @@ err_exit3:
 err_exit2:
 	clk_disable(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 err_exit1:
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
 	clk_disable(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index be94ed5..a66f33f 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -936,7 +936,6 @@ err_exit3:
 err_exit2:
 	clk_disable(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 err_exit1:
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
 	clk_disable(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
 
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 07e5784..18855ad 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1578,8 +1578,6 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	nand_release(&host->mtd);
 
 	return 0;
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
index cd6be2e..5211515 100644
--- a/drivers/mtd/nand/nuc900_nand.c
+++ b/drivers/mtd/nand/nuc900_nand.c
@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 
 	kfree(nuc900_nand);
 
-	platform_set_drvdata(pdev, NULL);
-
 	return 0;
 }
 
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 81b80af..daa3dfc 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -2087,7 +2087,6 @@ static int omap_nand_remove(struct platform_device *pdev)
 							mtd);
 	omap3_free_bch(&info->mtd);
 
-	platform_set_drvdata(pdev, NULL);
 	if (info->dma)
 		dma_release_channel(info->dma);
 
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 8fbd002..46f308d 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -186,7 +186,6 @@ no_dev:
 		clk_disable_unprepare(clk);
 		clk_put(clk);
 	}
-	platform_set_drvdata(pdev, NULL);
 	iounmap(io_base);
 no_res:
 	kfree(nc);
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index c004566..d42700a 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -122,7 +122,6 @@ static int plat_nand_probe(struct platform_device *pdev)
 out:
 	if (pdata->ctrl.remove)
 		pdata->ctrl.remove(pdev);
-	platform_set_drvdata(pdev, NULL);
 	iounmap(data->io_base);
 out_release_io:
 	release_mem_region(res->start, resource_size(res));
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 14d3db5..cd67f2a 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1165,7 +1165,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 		return 0;
 
 	pdata = pdev->dev.platform_data;
-	platform_set_drvdata(pdev, NULL);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq >= 0)
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d65afd2..191823e 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -697,8 +697,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 {
 	struct s3c2410_nand_info *info = to_nand_info(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (info == NULL)
 		return 0;
 
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 127bc42..1d41578 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -194,7 +194,6 @@ err_add:
 	nand_release(&sharpsl->mtd);
 
 err_scan:
-	platform_set_drvdata(pdev, NULL);
 	iounmap(sharpsl->io);
 err_ioremap:
 err_get_res:
@@ -212,8 +211,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
 	/* Release resources, unregister device */
 	nand_release(&sharpsl->mtd);
 
-	platform_set_drvdata(pdev, NULL);
-
 	iounmap(sharpsl->io);
 
 	/* Free the MTD device structure */
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 7ed654c..0488dd5 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -387,7 +387,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	int i;
 
-	platform_set_drvdata(dev, NULL);
 	if (!drvdata)
 		return 0;
 	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
index 9f11562..42520a3 100644
--- a/drivers/mtd/onenand/generic.c
+++ b/drivers/mtd/onenand/generic.c
@@ -94,8 +94,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
 	struct resource *res = pdev->resource;
 	unsigned long size = resource_size(res);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (info) {
 		onenand_release(&info->mtd);
 		release_mem_region(res->start, size);
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index d98b198..cd43cea 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -810,7 +810,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
-	platform_set_drvdata(pdev, NULL);
 	if (c->gpio_irq) {
 		free_irq(gpio_to_irq(c->gpio_irq), c);
 		gpio_free(c->gpio_irq);
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index 2cf7408..cebc48d 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -1073,7 +1073,6 @@ static int s3c_onenand_remove(struct platform_device *pdev)
 	release_mem_region(onenand->base_res->start,
 			   resource_size(onenand->base_res));
 
-	platform_set_drvdata(pdev, NULL);
 	kfree(onenand->oob_buf);
 	kfree(onenand->page_buf);
 	kfree(onenand);
-- 
1.7.10.4




From today at danbuy.dk  Tue Jun 25 01:31:38 2013
From: today at danbuy.dk (today at danbuy.dk)
Date: Tue, 25 Jun 2013 07:31:38 +0200
Subject: =?koi8-r?B?MTAtMTUgzcnO1dQg0M/LwdrBINfJxMXPINDSxcQgxMXR?=
 =?koi8-r?B?1MXM2M7P09TYwCDOxSDX08XHzyDUz8zYy88g0M/Nz8fV?=
 =?koi8-r?B?1CDXwc0gz9TSxdPUwdfSydLP18HU2CDN2dvD2SDJINfP?=
 =?koi8-r?B?2tfSwdTJ1Ngg2tLFzsnF?=
Message-ID: <065584180.20130625081132@danbuy.dk>

????????? ????? 10-15 ????? ? ??????, ?? ?????????? ???? 100-?????????? ?????? http://goo.gl/Ovzzd?/IuXfCDnF

From Anton.Prins at nl.bosch.com  Tue Jun 25 04:21:00 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Tue, 25 Jun 2013 10:21:00 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <51C005B8.3000709@intel.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
 <51C005B8.3000709@intel.com>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F546220@SI-MBX14.de.bosch.com>

Another weekend of tests, including the patches showed no more logging of writing orphan node 0.
Also the 0xdead4ead did not appear; so the patches certainly do their job!

We do not have hard evidence the missing root node is caused by this 'writing of free-ed memory'.
But at least it seems a good suspect! Because the occurrence is very low we will continue testing...
(And go back mounting synchronous to get some higher occurrence...)

I'll keep you up-to-date.

Anton


-----Original Message-----
From: Adrian Hunter [mailto:adrian.hunter at intel.com] 
Sent: dinsdag 18 juni 2013 9:01
To: Prins Anton (ST-CO/ENG1.1)
Cc: Mats K?rrman; linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: Re: UBIFS failure & stable page writes

On 18/06/13 09:31, Prins Anton (ST-CO/ENG1.1) wrote:
> Last night I did do additional tests with create/remove of files in a
> while loop on a synchronous mounted UBIFS. I did NOT get any node 0 or 1
> written over this night, but obvious enough I saw some strange node id in
> the orphan area: 0xdead4ead
> 
> 0xdead4ead Is known to me as SPINLOCK_MAGIC; but no glue why It is in the
> orphan area if node number... Is something known about 0xdead4ead?

I am afraid I have not had time to analyze the effects of the double-free
but it is reasonable to assume that UBIFS may be writing an orphan from a
structure that has been freed and therefore re-used by, for example in this
case, a spinlock.


From sambasiva.a at siennaecad.com  Tue Jun 25 07:21:28 2013
From: sambasiva.a at siennaecad.com (Samba Siva Reddy A)
Date: Tue, 25 Jun 2013 16:51:28 +0530
Subject: mtd_dataflash cause udev hang
Message-ID: <51C97D38.4000605@siennaecad.com>

Hi,

I am working on the at91sam9x5 boards. I added the DataFLash partitions
on board-sam9x5.c file.

It hangs while booting up the board after Starting udev message and
after that getting the following messages.

Starting udev

udevd (672): /proc/672/oom_adj is deprecated, please use

/proc/672/oom_score_adj

instead.

then these traces come out.

udevd[672]: worker [688] unexpectedly returned with status 0x0100

udevd[672]: worker [688] failed while handling

'/devices/virtual/block/loop0'

udevd[672]: worker [691] unexpectedly returned with status 0x0100

udevd[672]: worker [691] failed while handling

'/devices/virtual/block/loop1'

udevd[672]: worker [692] unexpectedly returned with status 0x0100


1.  Enable and ported the DMA Engine code from 2.6.39 kernel to

      3.2.6 kernel.


2. Added the below code snippet for avoiding the stack overflow

   while writing data to the dataFlash. I attached the file for your

   reference.


   static void *adjust_buffer_location(struct device *dev, void *buf) {

          if (likely(buf < high_memory)) {

           return buf;

           }

           else

           {

                   struct page *pg;

   

                   pg = vmalloc_to_page(buf);

                   if (pg == 0)

                   {

                           dev_err(dev, "failed to vmalloc_to_page\n");

   return NULL;

                   }

           return page_address(pg) + ((size_t)buf & ~PAGE_MASK);

           }

   }

   

   static int

   atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) {

   

   

       ptr = adjust_buffer_location(dev,(void *)xfer->tx_buf);

                   if(ptr)

                   xfer->tx_dma = dma_map_single(dev,

                                   ptr, xfer->len,

                                   DMA_TO_DEVICE);

                   if (dma_mapping_error(dev, xfer->tx_dma))

                           return -ENOMEM;

           }

           if (xfer->rx_buf) {

                   ptr=adjust_buffer_location(dev, xfer->rx_buf);

                   if(ptr)

                   xfer->rx_dma = dma_map_single(dev,

                                   ptr, xfer->len,

                                   DMA_FROM_DEVICE);

   

   }

Could you please help any one on this issue.

Regards
Samba



From jlu at pengutronix.de  Tue Jun 25 09:13:53 2013
From: jlu at pengutronix.de (Jan =?ISO-8859-1?Q?L=FCbbe?=)
Date: Tue, 25 Jun 2013 15:13:53 +0200
Subject: UBI leb_write_unlock NULL pointer Oops
In-Reply-To: <CAP+RiCCTo-_iH=bXuZMYY_BCMZjZzAkTB7Nm0_B0i2FErv+VAQ@mail.gmail.com>
References: <CAP+RiCCTo-_iH=bXuZMYY_BCMZjZzAkTB7Nm0_B0i2FErv+VAQ@mail.gmail.com>
Message-ID: <1372166033.4488.91.camel@coredoba.hi.pengutronix.de>

Hi,

On Mon, 2013-05-13 at 18:09 -0500, Brent Taylor wrote:
> I'm working with an atmel at91sam9g20 evaluation board
> (http://www.atmel.com/Images/doc6413.pdf) running the Linux kernel
> version 3.6.9.  On two occasions I have had the following Oops
> reported:
> 
> Unable to handle kernel NULL pointer dereference at virtual address 0000000c
> pgd = c313c000
> [0000000c] *pgd=231a5831, *pte=00000000, *ppte=00000000
> Internal error: Oops: 17 [#1] ARM
> Modules linked in:
> CPU: 0    Tainted: G        W     (3.6.9-00.04 #1)
> PC is at __up_write+0x34/0x16c
> LR is at leb_write_unlock+0x2c/0x88

> [<c013493c>] (__up_write+0x34/0x16c) from [<c01933d4>] (leb_write_unlock+0x2c/0x88)
> [<c01933d4>] (leb_write_unlock+0x2c/0x88) from [<c0193acc>] (ubi_eba_write_leb+0xa0/0x984)
> [<c0193acc>] (ubi_eba_write_leb+0xa0/0x984) from [<c0192874>] (ubi_leb_write+0xe0/0x124)
> [<c0192874>] (ubi_leb_write+0xe0/0x124) from [<c00dd268>] (ubifs_leb_write+0x9c/0x130)
> [<c00dd268>] (ubifs_leb_write+0x9c/0x130) from [<c00dde20>] (ubifs_wbuf_sync_nolock+0x104/0x34c)
> [<c00dde20>] (ubifs_wbuf_sync_nolock+0x104/0x34c) from [<c00d07bc>] (ubifs_jnl_update+0x2b8/0x60c)
> [<c00d07bc>] (ubifs_jnl_update+0x2b8/0x60c) from [<c00d7298>] (ubifs_create+0x108/0x1dc)
> [<c00d7298>] (ubifs_create+0x108/0x1dc) from [<c0089e60>] (vfs_create+0x84/0xb4)
> [<c0089e60>] (vfs_create+0x84/0xb4) from [<c008c94c>] (do_last.isra.38+0x78c/0xb90)
> [<c008c94c>] (do_last.isra.38+0x78c/0xb90) from [<c008cdf8>] (path_openat+0xa8/0x448)
> [<c008cdf8>] (path_openat+0xa8/0x448) from [<c008d47c>] (do_filp_open+0x2c/0x80)
> [<c008d47c>] (do_filp_open+0x2c/0x80) from [<c007f8d4>] (do_sys_open+0xe8/0x180)
> [<c007f8d4>] (do_sys_open+0xe8/0x180) from [<c00092c0>] (ret_fast_syscall+0x0/0x2c)
> Code: e5903004 e58d2004 e1560003 0a00002a (e593200c)
> ---[ end trace 287ddd4605e3394c ]---
> Kernel panic - not syncing: Fatal exception

I've seen the same traceback with 3.7.5, I seems to have something to do
with remounting read-only or failing to unmount a busy FS. Did you also
use remount?

You could also try to enable CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_MUTEXES
and CONFIG_DEBUG_LOCK_ALLOC, as the cash seems to happen during lock
operations.

Regards,
Jan L?bbe
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



From computersforpeace at gmail.com  Tue Jun 25 16:12:03 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Tue, 25 Jun 2013 13:12:03 -0700
Subject: [PATCH v6 00/10] mtd: add datasheet's ECC information to
 nand_chip{}
In-Reply-To: <1368760654-28754-1-git-send-email-b32955@freescale.com>
References: <1368760654-28754-1-git-send-email-b32955@freescale.com>
Message-ID: <CAN8TOE-QvScbPUEPyrs-fYVQZmPu1h-wWX2hjz46KYtaWRckBw@mail.gmail.com>

Hi Huang and others,

On Thu, May 16, 2013 at 8:17 PM, Huang Shijie <b32955 at freescale.com> wrote:
> 1.) Why add the ECC information to the nand_chip{} ?
>    Each nand chip has its requirement for the ECC correctability, such as
>    "4bit ECC for each 512Byte" or "40bit ECC for each 1024Byte".
>    This ECC info is very important to the nand controller, such as gpmi.
>
>    Take the Micron MT29F64G08CBABA for example, its geometry is
>    8k page size, 744 bytes oob size and it requires 40bit ECC per 1K bytes.
>    If we do not provide the ECC info to the gpmi nand driver, it has to
>    calculate the ECC correctability itself. The gpmi driver will gets the 56bit
>    ECC for per 1K bytes which is beyond its BCH's 40bit ecc capibility.
>    The gpmi will quits in this case. But in actually, the gpmi can supports
>    this nand chip if it can get the right ECC info.
>
> 2.) About the patch set:
>    2.1) patch 1:
>               The keynote patch.
>
>    2.2) patch 2 ~ patch 6:
>                These patches are for ONFI nand.
>                Parse out the ecc info from the parameter page if we can, else
>                parse out the ecc info from the extended parameter page.
>
>    2.2) patch 7 ~ patch 9:
>                Add the ECC info for full-id nand, and parse it out.
>
>    2.3) patch 10
>                The gpmi uses the ecc info to set the BCH module. and with this
>                patch set, the gpmi can supports the MT29F64G08CBABA now.

What's the status on this patch set? Surely by v6 we have some
reasonable stable state on things like naming. Does anyone have any
other objections? Unfortunately, I've been awfully distracted, and on
top of that, I'm running into some bugs with my NAND controller
sending the ONFI parameter read/change column commands. But any time
my controller actually outputs a correct parameter page + extended
parameter page, this series has worked for me.

I've put my 2 cents in on most of the issues I had, and I tested the
whole series on my driver at around v5. The only issues I have with it
are somewhat cosmetic and not worth bikeshedding. So for all the
non-GPMI specific stuff I'll give my:

Reviewed-by: Brian Norris <computersforpeace at gmail.com>
Tested-by: Brian Norris <computersforpeace at gmail.com>

Thanks for the work Huang.

Brian


From computersforpeace at gmail.com  Tue Jun 25 16:17:59 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Tue, 25 Jun 2013 13:17:59 -0700
Subject: [PATCH] mtd: nand: detect OOB size for Toshiba 24nm raw SLC
Message-ID: <1372191479-28470-1-git-send-email-computersforpeace@gmail.com>

Toshiba NAND datasheets have not been very forthcoming on OOB size
information; they do not provide any bitfields in the ID string for
spare area. In their 24nm technology flash, however, Toshiba migrated
their NAND to have 32 bytes spare per 512 bytes of page area (up from
the traditional 16 bytes), as they now require 8-bit ECC or higher.

I have discussed this issue directly with Toshiba representatives, and
they acknowledge this problem. They recommend detecting these flash
based on their technology node as follows:

  For 24nm Toshiba SLC raw NAND (not BENAND -- Built-in Ecc NAND), there
  are 32 bytes of spare area for every 512 bytes of in-band data area.

We can implement this rule with the following snippet of a device ID
decode table, which applies to all their 43nm, 32nm, and 24nm SLC NAND
(this table is not fully in the NAND datasheets, but it was provided
directly by Toshiba representatives):

  - ID byte 5, bit[7]:
          1    -> BENAND
          0    -> raw SLC

  - ID byte 6, bits[2:0]:
          100b -> 43nm
          101b -> 32nm
          110b -> 24nm
          111b -> Reserved

I'm also working with Toshiba on including this bitfield description for
their 5th and 6th ID bytes in their public data sheets.

I will provide the 8-byte ID strings from the two 24nm Toshiba samples I
have; their first 6 bytes match the documentation I received from
Toshiba:

  24nm SLC 1Gbit TC58NVG0S3HTA00
  0x98 0xf1 0x80 0x15 0x72 0x16 0x08 0x00

  24nm SLC 2Gbit TC58NVG1S3HTA00
  0x98 0xda 0x90 0x15 0x76 0x16 0x08 0x00

I have also tested for regressions with:

  43nm SLC 4Gbit TC58NVG2S3ETA00
  0x98 0xdc 0x90 0x15 0x76 0x14 0x03 0x10

  32nm SLC 8Gbit TC58NVG3SOFA00
  0x98 0xd3 0x90 0x26 0x76 0x15 0x02 0x08

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/nand/nand_base.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 1cbacff..3e56995 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3079,6 +3079,22 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
 		extid >>= 2;
 		/* Get buswidth information */
 		*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+
+		/*
+		 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+		 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+		 * follows:
+		 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+		 *                         110b -> 24nm
+		 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+		 */
+		if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+				!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+				(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+				!(id_data[4] & 0x80) /* !BENAND */) {
+			mtd->oobsize = 32 * mtd->writesize >> 9;
+		}
+
 	}
 }
 
-- 
1.8.3.1



From sourav.poddar at ti.com  Wed Jun 26 03:41:09 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Wed, 26 Jun 2013 13:11:09 +0530
Subject: [PATCH 0/3] spi/mtd generic framework,
 ti qspi controller and spansion driver
Message-ID: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>

This patch series add support for the generic spi based flash
framework(spinand_mtd), which can be used used by any spi based flash device to
attach itself to mtd framework. 

The first patch of this series includes both the generic framework and the
the micron device(spinand_lld) making use of the framework.
I picked the first patch as a standalone patch. Can split the generic and
the lld part based on community suggestions.

The second patch is the ti qspi controller driver.
The third patch is the spansion s25fl256s driver, making use of the the
generic spinand_mtd frameowrk.

Test info:
Tested the generic framework(spinand_mtd.c) along with patch(2&3) on my dra7xx board 
for write/erase/read using nand utils.

Compile tested(spinand_lld.c).

Mona Anonuevo (1):
  drivers: mtd: spinand: Add generic spinand frameowrk and micron
    driver.

Sourav Poddar (2):
  drivers: spi: Add qspi flash controller
  drivers: mtd: spinand: Add qspi spansion flash controller

 drivers/mtd/Kconfig                 |    2 +
 drivers/mtd/Makefile                |    2 +
 drivers/mtd/spinand/Kconfig         |   31 ++
 drivers/mtd/spinand/Makefile        |   10 +
 drivers/mtd/spinand/spinand_lld.c   |  776 +++++++++++++++++++++++++++++++++++
 drivers/mtd/spinand/spinand_mtd.c   |  690 +++++++++++++++++++++++++++++++
 drivers/mtd/spinand/ti-qspi-flash.c |  373 +++++++++++++++++
 drivers/spi/Kconfig                 |    6 +
 drivers/spi/Makefile                |    1 +
 drivers/spi/ti-qspi.c               |  352 ++++++++++++++++
 include/linux/mtd/spinand.h         |  155 +++++++
 11 files changed, 2398 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/spinand/Kconfig
 create mode 100644 drivers/mtd/spinand/Makefile
 create mode 100644 drivers/mtd/spinand/spinand_lld.c
 create mode 100644 drivers/mtd/spinand/spinand_mtd.c
 create mode 100644 drivers/mtd/spinand/ti-qspi-flash.c
 create mode 100644 drivers/spi/ti-qspi.c
 create mode 100644 include/linux/mtd/spinand.h



From sourav.poddar at ti.com  Wed Jun 26 03:41:10 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Wed, 26 Jun 2013 13:11:10 +0530
Subject: [PATCH 1/3] drivers: mtd: spinand: Add generic spinand frameowrk and
 micron driver.
In-Reply-To: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
Message-ID: <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>

From: Mona Anonuevo <manonuevo at micron.com>

This patch adds support for a generic spinand framework(spinand_mtd.c).
This frameowrk can be used for other spi based flash devices also. The idea
is to have a common model under drivers/mtd, as also present for other no spi
devices(there is a generic framework and device part simply attaches itself to it.)

The generic frework will be used later by me for a SPI based spansion S25FL256 device.
The patch also contains a micron driver attaching itself to generic framework.

Signed-off-by: Mona Anonuevo <manonuevo at micron.com>
Signed-off-by: Tuan Nguyen <tqnguyen at micron.com>
Signed-off-by: Sourav Poddar <sourav.poddar at ti.com>
----
[I picked this as a standalone patch, can split it into generic and device part
based on community feedback.]

 drivers/mtd/Kconfig               |    2 +
 drivers/mtd/Makefile              |    2 +
 drivers/mtd/spinand/Kconfig       |   24 ++
 drivers/mtd/spinand/Makefile      |   10 +
 drivers/mtd/spinand/spinand_lld.c |  776 +++++++++++++++++++++++++++++++++++++
 drivers/mtd/spinand/spinand_mtd.c |  690 +++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h       |  155 ++++++++
 7 files changed, 1659 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/spinand/Kconfig
 create mode 100644 drivers/mtd/spinand/Makefile
 create mode 100644 drivers/mtd/spinand/spinand_lld.c
 create mode 100644 drivers/mtd/spinand/spinand_mtd.c
 create mode 100644 include/linux/mtd/spinand.h

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 5fab4e6..c9e6c60 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -318,6 +318,8 @@ source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/onenand/Kconfig"
 
+source "drivers/mtd/spinand/Kconfig"
+
 source "drivers/mtd/lpddr/Kconfig"
 
 source "drivers/mtd/ubi/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4cfb31e..cce68db 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -32,4 +32,6 @@ inftl-objs		:= inftlcore.o inftlmount.o
 
 obj-y		+= chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
 
+obj-y		+= spinand/
+
 obj-$(CONFIG_MTD_UBI)		+= ubi/
diff --git a/drivers/mtd/spinand/Kconfig b/drivers/mtd/spinand/Kconfig
new file mode 100644
index 0000000..38c739f
--- /dev/null
+++ b/drivers/mtd/spinand/Kconfig
@@ -0,0 +1,24 @@
+#
+# linux/drivers/mtd/spinand/Kconfig
+#
+
+menuconfig MTD_SPINAND
+	tristate "SPINAND Device Support"
+	depends on MTD
+	help
+	 This enables support for accessing Micron SPI NAND flash
+	 devices.
+
+if MTD_SPINAND
+
+config MTD_SPINAND_ONDIEECC
+	bool "Use SPINAND internal ECC"
+	help
+	 Internel ECC
+
+config MTD_SPINAND_SWECC
+	bool "Use software ECC"
+	depends on MTD_NAND
+	help
+	 software ECC
+endif
diff --git a/drivers/mtd/spinand/Makefile b/drivers/mtd/spinand/Makefile
new file mode 100644
index 0000000..355e726
--- /dev/null
+++ b/drivers/mtd/spinand/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the SPI NAND MTD
+#
+
+# Core functionality.
+obj-$(CONFIG_MTD_SPINAND)		+= spinand.o
+
+spinand-objs := spinand_mtd.o spinand_lld.o
+
+
diff --git a/drivers/mtd/spinand/spinand_lld.c b/drivers/mtd/spinand/spinand_lld.c
new file mode 100644
index 0000000..9f53737
--- /dev/null
+++ b/drivers/mtd/spinand/spinand_lld.c
@@ -0,0 +1,776 @@
+/*
+spinand_lld.c
+
+Copyright (c) 2009-2010 Micron Technology, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/math64.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spinand.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#define mu_spi_nand_driver_version "Beagle-MTD_01.00_Linux2.6.33_20100507"
+#define SPI_NAND_MICRON_DRIVER_KEY 0x1233567
+
+/****************************************************************************/
+
+/**
+   OOB area specification layout:  Total 32 available free bytes.
+*/
+static struct nand_ecclayout spinand_oob_64 = {
+	.eccbytes = 24,
+	.eccpos = {
+		   1, 2, 3, 4, 5, 6,
+		   17, 18, 19, 20, 21, 22,
+		   33, 34, 35, 36, 37, 38,
+		   49, 50, 51, 52, 53, 54, },
+	.oobavail = 32,
+	.oobfree = {
+		{.offset = 8,
+		 .length = 8},
+		{.offset = 24,
+		 .length = 8},
+		{.offset = 40,
+		 .length = 8},
+		{.offset = 56,
+		 .length = 8}, }
+};
+/**
+ * spinand_cmd - to process a command to send to the SPI Nand
+ *
+ * Description:
+ *    Set up the command buffer to send to the SPI controller.
+ *    The command buffer has to initized to 0
+ */
+int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
+{
+	int					ret;
+	struct spi_message	message;
+	struct spi_transfer		x[4];
+	u8 dummy = 0xff;
+
+	spi_message_init(&message);
+	memset(x, 0, sizeof(x));
+
+	x[0].len = 1;
+	x[0].tx_buf = &cmd->cmd;
+	spi_message_add_tail(&x[0], &message);
+
+	if (cmd->n_addr) {
+		x[1].len = cmd->n_addr;
+		x[1].tx_buf = cmd->addr;
+		spi_message_add_tail(&x[1], &message);
+	}
+
+	if (cmd->n_dummy) {
+		x[2].len = cmd->n_dummy;
+		x[2].tx_buf = &dummy;
+		spi_message_add_tail(&x[2], &message);
+	}
+
+	if (cmd->n_tx) {
+		x[3].len = cmd->n_tx;
+		x[3].tx_buf = cmd->tx_buf;
+		spi_message_add_tail(&x[3], &message);
+	}
+
+	if (cmd->n_rx) {
+		x[3].len = cmd->n_rx;
+		x[3].rx_buf = cmd->rx_buf;
+		spi_message_add_tail(&x[3], &message);
+	}
+
+	ret = spi_sync(spi, &message);
+
+	return ret;
+}
+
+/**
+ * spinand_reset- send reset command "0xff" to the Nand device
+ *
+ * Description:
+ *    Reset the SPI Nand with the reset command 0xff
+*/
+static int spinand_reset(struct spi_device *spi_nand)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = CMD_RESET;
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_read_id- Read SPI Nand ID
+ *
+ * Description:
+ *    Read ID: read two ID bytes from the SPI Nand device
+*/
+static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
+{
+	struct spinand_cmd cmd = {0};
+	ssize_t retval;
+
+	cmd.cmd = CMD_READ_ID;
+	cmd.n_dummy = 1;
+	cmd.n_rx = 2;
+	cmd.rx_buf = id;
+
+	retval = spinand_cmd(spi_nand, &cmd);
+
+	if (retval != 0) {
+		dev_err(&spi_nand->dev, "error %d reading id\n",
+				(int) retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * spinand_lock_block- send write register 0x1f command to the Nand device
+ *
+ * Description:
+ *    After power up, all the Nand blocks are locked.  This function allows
+ *    one to unlock the blocks, and so it can be wriiten or erased.
+*/
+static int spinand_lock_block(struct spi_device *spi_nand,
+			struct spinand_info *info, u8 lock)
+{
+	struct spinand_cmd cmd = {0};
+	ssize_t retval;
+
+	cmd.cmd = CMD_WRITE_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_BLOCK_LOCK;
+	cmd.n_tx = 1;
+	cmd.tx_buf = &lock;
+
+	retval = spinand_cmd(spi_nand, &cmd);
+
+	if (retval != 0) {
+		dev_err(&spi_nand->dev, "error %d lock block\n",
+				(int) retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * spinand_read_status- send command 0xf to the SPI Nand status register
+ *
+ * Description:
+ * After read, write, or erase, the Nand device is expected to
+	set the busy status.
+ * This function is to allow reading the status of the command:
+	read, write, and erase.
+ * Once the status turns to be ready, the other status bits also
+	are valid status bits.
+*/
+static int spinand_read_status(struct spi_device *spi_nand,
+			struct spinand_info *info, u8 *status)
+{
+	struct spinand_cmd cmd = {0};
+	ssize_t retval;
+
+	cmd.cmd = CMD_READ_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_STATUS;
+	cmd.n_rx = 1;
+	cmd.rx_buf = status;
+
+	retval = spinand_cmd(spi_nand, &cmd);
+
+	if (retval != 0) {
+		dev_err(&spi_nand->dev, "error %d reading status register\n",
+				(int) retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * spinand_get_otp- send command 0xf to read the SPI Nand OTP register
+ *
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+ */
+static int spinand_get_otp(struct spi_device *spi_nand,
+			struct spinand_info *info, u8 *otp)
+{
+	struct spinand_cmd cmd = {0};
+	ssize_t retval;
+
+	cmd.cmd = CMD_READ_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_OTP;
+	cmd.n_rx = 1;
+	cmd.rx_buf	 = otp;
+
+	retval = spinand_cmd(spi_nand, &cmd);
+
+	if (retval != 0) {
+		dev_err(&spi_nand->dev, "error %d get otp\n",
+				(int) retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * spinand_set_otp- send command 0x1f to write the SPI Nand OTP register
+ *
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+*/
+static int spinand_set_otp(struct spi_device *spi_nand,
+			struct spinand_info *info, u8 *otp)
+{
+	struct spinand_cmd cmd = {0};
+	ssize_t retval;
+
+	cmd.cmd = CMD_WRITE_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_OTP;
+	cmd.n_tx = 1;
+	cmd.tx_buf = otp;
+
+	retval = spinand_cmd(spi_nand, &cmd);
+
+	if (retval != 0) {
+		dev_err(&spi_nand->dev, "error %d set otp\n",
+			(int) retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * sspinand_enable_ecc- send command 0x1f to write the SPI Nand OTP register
+ *
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+*/
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+static int spinand_enable_ecc(struct spi_device *spi_nand,
+			struct spinand_info *info)
+{
+	ssize_t retval;
+	u8 otp = 0;
+
+	retval = spinand_get_otp(spi_nand, info, &otp);
+
+	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
+		return 0;
+	} else {
+		otp |= OTP_ECC_MASK;
+		retval = spinand_set_otp(spi_nand, info, &otp);
+		retval = spinand_get_otp(spi_nand, info, &otp);
+		return retval;
+	}
+}
+#else
+static int spinand_disable_ecc(struct spi_device *spi_nand,
+				struct spinand_info *info)
+{
+	ssize_t retval;
+	u8 otp = 0;
+
+	retval = spinand_get_otp(spi_nand, info, &otp);
+
+	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
+		otp &= ~OTP_ECC_MASK;
+		retval = spinand_set_otp(spi_nand, info, &otp);
+		retval = spinand_get_otp(spi_nand, info, &otp);
+		return retval;
+	} else {
+		return 0;
+	}
+}
+#endif
+
+/**
+ * sspinand_write_enable- send command 0x06 to enable write or erase the Nand cells
+ *
+ * Description:
+ *   Before write and erase the Nand cells, the write enable has to be set.
+ *   After the write or erase, the write enable bit is automatically
+	cleared( status register bit 2 )
+ *   Set the bit 2 of the status register has the same effect
+*/
+static int spinand_write_enable(struct spi_device *spi_nand,
+					struct spinand_info *info)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = CMD_WR_ENABLE;
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+static int spinand_read_page_to_cache(struct spi_device *spi_nand,
+					struct spinand_info *info, u16 page_id)
+{
+	struct spinand_cmd cmd = {0};
+	u16 row;
+
+	row = page_id;
+
+	cmd.cmd = CMD_READ;
+	cmd.n_addr = 3;
+	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
+	cmd.addr[2] = (u8)(row & 0x00ff);
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_read_from_cache- send command 0x03 to read out the data from the
+	cache register( 2112 bytes max )
+ *
+ * Description:
+ *   The read can specify 1 to 2112 bytes of data read at the
+	coresponded locations.
+ *   No tRd delay.
+*/
+static int spinand_read_from_cache(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 byte_id, u16 len, u8 *rbuf)
+{
+	struct spinand_cmd cmd = {0};
+	u16 column;
+
+	column = byte_id;
+
+	cmd.cmd = CMD_READ_RDM;
+	cmd.n_addr = 2;
+	cmd.addr[0] = (u8)((column&0xff00)>>8);
+	cmd.addr[1] = (u8)(column&0x00ff);
+	cmd.n_dummy = 1;
+	cmd.n_rx = len;
+	cmd.rx_buf = rbuf;
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_read_page-to read a page with:
+ * @page_id: the physical page number
+ * @offset:  the location from 0 to 2111
+ * @len:     number of bytes to read
+ * @rbuf:    read buffer to hold @len bytes
+ *
+ * Description:
+ *   The read icludes two commands to the Nand: 0x13 and 0x03 commands
+ *   Poll to read status to wait for tRD time.
+ */
+static int spinand_read_page(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 page_id, u16 offset,
+			u16 len, u8 *rbuf)
+{
+	ssize_t retval;
+	u8 status = 0;
+
+	retval = spinand_read_page_to_cache(spi_nand, info, page_id);
+
+	while (1) {
+		retval = spinand_read_status(spi_nand, info, &status);
+		if (retval < 0) {
+			dev_err(&spi_nand->dev, "error %d reading status register\n",
+					(int) retval);
+			return retval;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
+				dev_err(&spi_nand->dev,
+					"ecc error, page=%d\n", page_id);
+			}
+			break;
+		}
+	}
+
+	retval = spinand_read_from_cache(spi_nand, info, offset, len, rbuf);
+	return 0;
+}
+
+/**
+ * spinand_program_data_to_cache--to write a page to cache with:
+ * @byte_id: the location to write to the cache
+ * @len:     number of bytes to write
+ * @rbuf:    read buffer to hold @len bytes
+ *
+ * Description:
+ *   The write command used here is 0x84--indicating that the cache
+	is not cleared first.
+ *   Since it is writing the data to cache, there is no tPROG time.
+ */
+static int spinand_program_data_to_cache(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 byte_id, u16 len, u8 *wbuf)
+{
+	struct spinand_cmd cmd = {0};
+	u16 column;
+
+	column = byte_id;
+
+	cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
+	cmd.n_addr = 2;
+	cmd.addr[0] = (u8)((column & 0xff00) >> 8);
+	cmd.addr[1] = (u8)(column & 0x00ff);
+	cmd.n_tx = len;
+	cmd.tx_buf = wbuf;
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_program_execute--to write a page from cache to the Nand array with:
+ * @page_id: the physical page location to write the page.
+ *
+ * Description:
+ *   The write command used here is 0x10--indicating the cache is
+	writing to the Nand array.
+ *   Need to wait for tPROG time to finish the transaction.
+ */
+static int spinand_program_execute(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 page_id)
+{
+	struct spinand_cmd cmd = {0};
+	u16 row;
+
+	row = page_id;
+
+	cmd.cmd = CMD_PROG_PAGE_EXC;
+	cmd.n_addr = 3;
+	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
+	cmd.addr[2] = (u8)(row & 0x00ff);
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_program_page--to write a page with:
+ * @page_id: the physical page location to write the page.
+ * @offset:  the location from the cache starting from 0 to 2111
+ * @len:     the number of bytes to write
+ * @wbuf:    the buffer to hold the number of bytes
+ *
+ * Description:
+ *   The commands used here are 0x06, 0x84, and 0x10--indicating that
+	the write enable is first
+ *   sent, the write cache command, and the write execute command
+ *   Poll to wait for the tPROG time to finish the transaction.
+ */
+static int spinand_program_page(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 page_id, u16 offset,
+		u16 len, u8 *wbuf)
+{
+	ssize_t retval;
+	u8 status = 0;
+
+	retval = spinand_write_enable(spi_nand, info);
+
+	retval = spinand_program_data_to_cache(spi_nand, info, offset,
+			len, wbuf);
+
+	retval = spinand_program_execute(spi_nand, info, page_id);
+
+	while (1) {
+		retval = spinand_read_status(spi_nand, info, &status);
+		if (retval < 0) {
+			dev_err(&spi_nand->dev,
+				"error %d reading status register\n",
+					(int) retval);
+			return retval;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) {
+				dev_err(&spi_nand->dev,
+					"program error, page=%d\n", page_id);
+				return -1;
+			}
+		} else {
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * spinand_erase_block_erase--to erase a page with:
+ * @block_id: the physical block location to erase.
+ *
+ * Description:
+ *   The command used here is 0xd8--indicating an erase
+command to erase one block--64 pages
+ *   Need to wait for tERS.
+ */
+static int spinand_erase_block_erase(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 block_id)
+{
+	struct spinand_cmd cmd = {0};
+	u16 row;
+
+	row = block_id << 6;
+	cmd.cmd = CMD_ERASE_BLK;
+	cmd.n_addr = 3;
+	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
+	cmd.addr[2] = (u8)(row & 0x00ff);
+
+	return spinand_cmd(spi_nand, &cmd);
+}
+
+/**
+ * spinand_erase_block--to erase a page with:
+ * @block_id: the physical block location to erase.
+ *
+ * Description:
+ *   The commands used here are 0x06 and 0xd8--indicating an erase
+	command to erase one block--64 pages
+ *   It will first to enable the write enable bit ( 0x06 command ),
+	and then send the 0xd8 erase command
+ *   Poll to wait for the tERS time to complete the tranaction.
+ */
+static int spinand_erase_block(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 block_id)
+{
+	ssize_t retval;
+	u8 status = 0;
+
+	retval = spinand_write_enable(spi_nand, info);
+
+	retval = spinand_erase_block_erase(spi_nand, info, block_id);
+
+	while (1) {
+		retval = spinand_read_status(spi_nand, info, &status);
+		if (retval < 0) {
+			dev_err(&spi_nand->dev,
+				"error %d reading status register\n",
+					(int) retval);
+			return retval;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) {
+				dev_err(&spi_nand->dev,
+					"erase error, block=%d\n", block_id);
+				return -1;
+			} else {
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * spinand_get_info: get NAND info, from read id or const value
+ * Description:
+ *   To set up the device parameters.
+ */
+static int spinand_get_info(struct spi_device *spi_nand,
+		struct spinand_info *info, u8 *id)
+{
+	if (id[0] == 0x2C && (id[1] == 0x11 ||
+		id[1] == 0x12 || id[1] == 0x13)) {
+		info->mid = id[0];
+		info->did = id[1];
+		info->name = "MT29F1G01ZAC";
+		info->nand_size = (1024 * 64 * 2112);
+		info->usable_size = (1024 * 64 * 2048);
+		info->block_size = (2112*64);
+		info->block_main_size = (2048*64);
+		info->block_num_per_chip = 1024;
+		info->page_size = 2112;
+		info->page_main_size = 2048;
+		info->page_spare_size = 64;
+		info->page_num_per_block = 64;
+
+		info->block_shift = 17;
+		info->block_mask = 0x1ffff;
+
+		info->page_shift = 11;
+		info->page_mask = 0x7ff;
+
+		info->ecclayout = &spinand_oob_64;
+	}
+	return 0;
+}
+
+/**
+ * spinand_probe - [spinand Interface]
+ * @spi_nand: registered device driver.
+ *
+ * Description:
+ *   To set up the device driver parameters to make the device available.
+*/
+static int spinand_probe(struct spi_device *spi_nand)
+{
+	ssize_t retval;
+	struct mtd_info *mtd;
+	struct spinand_chip *chip;
+	struct spinand_info *info;
+	struct flash_platform_data      *data;
+	struct mtd_part_parser_data     ppdata;
+	u8 id[2] = {0};
+
+	retval = spinand_reset(spi_nand);
+	retval = spinand_reset(spi_nand);
+	retval = spinand_read_id(spi_nand, (u8 *)&id);
+	if (id[0] == 0 && id[1] == 0) {
+		pr_info(KERN_INFO "SPINAND: read id error! 0x%02x, 0x%02x!\n",
+			id[0], id[1]);
+		return 0;
+	}
+
+	data = spi_nand->dev.platform_data;
+	info  = kzalloc(sizeof(struct spinand_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	retval = spinand_get_info(spi_nand, info, (u8 *)&id);
+	pr_info(KERN_INFO "SPINAND: 0x%02x, 0x%02x, %s\n",
+		id[0], id[1], info->name);
+	pr_info(KERN_INFO "%s\n", mu_spi_nand_driver_version);
+	retval = spinand_lock_block(spi_nand, info, BL_ALL_UNLOCKED);
+
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	retval = spinand_enable_ecc(spi_nand, info);
+#else
+	retval = spinand_disable_ecc(spi_nand, info);
+#endif
+
+	ppdata.of_node = spi_nand->dev.of_node;
+
+	chip  = kzalloc(sizeof(struct spinand_chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->spi_nand = spi_nand;
+	chip->info = info;
+	chip->reset = spinand_reset;
+	chip->read_id = spinand_read_id;
+	chip->read_page = spinand_read_page;
+	chip->program_page = spinand_program_page;
+	chip->erase_block = spinand_erase_block;
+
+	chip->buf = kzalloc(info->page_size, GFP_KERNEL);
+	if (!chip->buf)
+		return -ENOMEM;
+
+	chip->oobbuf = kzalloc(info->ecclayout->oobavail, GFP_KERNEL);
+	if (!chip->oobbuf)
+		return -ENOMEM;
+
+	mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
+	if (!mtd)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi_nand->dev, mtd);
+
+	mtd->priv = chip;
+
+	retval = spinand_mtd(mtd);
+
+	return mtd_device_parse_register(mtd, NULL, &ppdata,
+			data ? data->parts : NULL,
+			data ? data->nr_parts : 0);
+}
+
+/**
+ * __devexit spinand_remove--Remove the device driver
+ * @spi: the spi device.
+ *
+ * Description:
+ *   To remove the device driver parameters and free up allocated memories.
+ */
+static int spinand_remove(struct spi_device *spi)
+{
+	struct mtd_info *mtd;
+	struct spinand_chip *chip;
+
+	pr_debug("%s: remove\n", dev_name(&spi->dev));
+
+	mtd = dev_get_drvdata(&spi->dev);
+
+	mtd_device_unregister(mtd);
+
+	chip = mtd->priv;
+
+	kfree(chip->info);
+	kfree(chip->buf);
+	kfree(chip->oobbuf);
+	kfree(chip);
+	kfree(mtd);
+
+	return 0;
+}
+
+/**
+ * Device name structure description
+*/
+static struct spi_driver spinand_driver = {
+	.driver = {
+		.name		= "spi_nand",
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+
+	.probe		= spinand_probe,
+	.remove		= spinand_remove,
+};
+
+/**
+ * Device driver registration
+*/
+static int __init spinand_init(void)
+{
+	return spi_register_driver(&spinand_driver);
+}
+
+/**
+ * unregister Device driver.
+*/
+static void __exit spinand_exit(void)
+{
+	spi_unregister_driver(&spinand_driver);
+}
+
+module_init(spinand_init);
+module_exit(spinand_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Henry Pan<hspan at micron.com>");
+MODULE_DESCRIPTION("SPI NAND driver code");
diff --git a/drivers/mtd/spinand/spinand_mtd.c b/drivers/mtd/spinand/spinand_mtd.c
new file mode 100644
index 0000000..8bfff86
--- /dev/null
+++ b/drivers/mtd/spinand/spinand_mtd.c
@@ -0,0 +1,690 @@
+/*
+spinand_mtd.c
+
+Copyright (c) 2009-2010 Micron Technology, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spinand.h>
+#include <linux/mtd/nand_ecc.h>
+
+/**
+ * spinand_get_device - [GENERIC] Get chip for selected access
+ * @param mtd		MTD device structure
+ * @param new_state	the state which is requested
+ *
+ * Get the device and lock it for exclusive access
+ */
+#define mu_spi_nand_driver_version "Beagle-MTD_01.00_Linux2.6.33_20100507"
+
+static int spinand_get_device(struct mtd_info *mtd, int new_state)
+{
+	struct spinand_chip *this = mtd->priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * Grab the lock and see if the device is available
+	 */
+	while (1) {
+		spin_lock(&this->chip_lock);
+		if (this->state == FL_READY) {
+			this->state = new_state;
+			spin_unlock(&this->chip_lock);
+			break;
+		}
+		if (new_state == FL_PM_SUSPENDED) {
+			spin_unlock(&this->chip_lock);
+			return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&this->wq, &wait);
+		spin_unlock(&this->chip_lock);
+		schedule();
+		remove_wait_queue(&this->wq, &wait);
+	}
+	return 0;
+}
+
+/**
+ * spinand_release_device - [GENERIC] release chip
+ * @param mtd		MTD device structure
+ *
+ * Deselect, release chip lock and wake up anyone waiting on the device
+ */
+static void spinand_release_device(struct mtd_info *mtd)
+{
+	struct spinand_chip *this = mtd->priv;
+
+	/* Release the chip */
+	spin_lock(&this->chip_lock);
+	this->state = FL_READY;
+	wake_up(&this->wq);
+	spin_unlock(&this->chip_lock);
+}
+
+#ifdef CONFIG_MTD_SPINAND_SWECC
+static void spinand_calculate_ecc(struct mtd_info *mtd)
+{
+	int i;
+	int eccsize = 512;
+	int eccbytes = 3;
+	int eccsteps = 4;
+	int ecctotal = 12;
+	struct spinand_chip *chip = mtd->priv;
+	struct spinand_info *info = chip->info;
+	unsigned char *p = chip->buf;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
+
+	for (i = 0; i < ecctotal; i++)
+		chip->buf[info->page_main_size +
+			info->ecclayout->eccpos[i]] = chip->ecc_calc[i];
+}
+
+static int spinand_correct_data(struct mtd_info *mtd)
+{
+	int i;
+	int eccsize = 512;
+	int eccbytes = 3;
+	int eccsteps = 4;
+	int ecctotal = 12;
+	struct spinand_chip *chip = mtd->priv;
+	struct spinand_info *info = chip->info;
+	unsigned char *p = chip->buf;
+	int errcode = 0;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+		__nand_calculate_ecc(p, eccsize, &chip->ecc_calc[i]);
+
+	for (i = 0; i < ecctotal; i++)
+		chip->ecc_code[i] = chip->buf[info->page_main_size +
+					info->ecclayout->eccpos[i]];
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		int stat;
+
+		stat = __nand_correct_data(p, &chip->ecc_code[i],
+					&chip->ecc_calc[i], eccsize);
+		if (stat < 0)
+			errcode = -1;
+		else if (stat == 1)
+			errcode = 1;
+	}
+	return errcode;
+}
+#endif
+
+static int spinand_read_ops(struct mtd_info *mtd, loff_t from,
+			  struct mtd_oob_ops *ops)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spi_device *spi_nand = chip->spi_nand;
+	struct spinand_info *info = chip->info;
+	int page_id, page_offset, page_num, oob_num;
+
+	int count;
+	int main_ok, main_left, main_offset;
+	int oob_ok, oob_left;
+
+	signed int retval;
+	signed int errcode = 0;
+
+	if (!chip->buf)
+		return -1;
+
+	page_id = from >> info->page_shift;
+
+	/* for main data */
+	page_offset = from & info->page_mask;
+	page_num = (page_offset + ops->len +
+			info->page_main_size - 1) / info->page_main_size;
+
+	/* for oob */
+	if (info->ecclayout->oobavail)
+		oob_num = (ops->ooblen +
+			info->ecclayout->oobavail - 1) / info->ecclayout->oobavail;
+	else
+		oob_num = 0;
+
+	count = 0;
+
+	main_left = ops->len;
+	main_ok = 0;
+	main_offset = page_offset;
+
+	oob_left = ops->ooblen;
+	oob_ok = 0;
+
+	while (1) {
+		if (count < page_num || count < oob_num) {
+			memset(chip->buf, 0, info->page_size);
+			retval = chip->read_page(spi_nand, info,
+				page_id + count, 0, info->page_size,
+					chip->buf);
+			if (retval != 0) {
+				errcode = -1;
+				pr_info(KERN_INFO
+					"spinand_read_ops: fail, page=%d!\n",
+						page_id);
+				return errcode;
+			}
+		} else {
+			break;
+		}
+		if (count < page_num && ops->datbuf) {
+			int size;
+
+#ifdef CONFIG_MTD_SPINAND_SWECC
+			retval = spinand_correct_data(mtd);
+			if (retval == -1)
+				pr_info(KERN_INFO
+					"SWECC uncorrectable error! page=%x\n",
+					page_id+count);
+			else if (retval == 1)
+				pr_info(KERN_INFO
+					"SWECC 1 bit error, corrected! page=%x\n",
+					page_id+count);
+#endif
+
+			if ((main_offset + main_left) < info->page_main_size)
+				size = main_left;
+			else
+				size = info->page_main_size - main_offset;
+
+			memcpy(ops->datbuf + main_ok, chip->buf, size);
+
+			main_ok += size;
+			main_left -= size;
+			main_offset = 0;
+			ops->retlen = main_ok;
+		}
+
+		if (count < oob_num && ops->oobbuf && chip->oobbuf) {
+			int size;
+			int offset, len, temp;
+
+			/* repack spare to oob */
+			memset(chip->oobbuf, 0, info->ecclayout->oobavail);
+
+			temp = 0;
+			offset = info->ecclayout->oobfree[0].offset;
+			len = info->ecclayout->oobfree[0].length;
+			memcpy(chip->oobbuf + temp,
+				chip->buf + info->page_main_size + offset, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[1].offset;
+			len = info->ecclayout->oobfree[1].length;
+			memcpy(chip->oobbuf + temp,
+				chip->buf + info->page_main_size + offset, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[2].offset;
+			len = info->ecclayout->oobfree[2].length;
+			memcpy(chip->oobbuf + temp,
+				chip->buf + info->page_main_size + offset, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[3].offset;
+			len = info->ecclayout->oobfree[3].length;
+			memcpy(chip->oobbuf + temp,
+				chip->buf + info->page_main_size + offset, len);
+
+			/* copy oobbuf to ops oobbuf */
+			if (oob_left < info->ecclayout->oobavail)
+				size = oob_left;
+			else
+				size = info->ecclayout->oobavail;
+
+			memcpy(ops->oobbuf + oob_ok, chip->oobbuf, size);
+
+			oob_ok += size;
+			oob_left -= size;
+
+			ops->oobretlen = oob_ok;
+		}
+		count++;
+	}
+	return errcode;
+}
+
+static int spinand_write_ops(struct mtd_info *mtd, loff_t to,
+			 struct mtd_oob_ops *ops)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spi_device *spi_nand = chip->spi_nand;
+	struct spinand_info *info = chip->info;
+	int page_id, page_offset, page_num, oob_num;
+
+	int count;
+
+	int main_ok, main_left, main_offset;
+	int oob_ok, oob_left;
+
+	signed int retval;
+	signed int errcode = 0;
+
+	if (!chip->buf)
+		return -1;
+
+	page_id = to >> info->page_shift;
+
+	/* for main data */
+	page_offset = to & info->page_mask;
+	page_num = (page_offset + ops->len +
+			info->page_main_size - 1) / info->page_main_size;
+
+	/* for oob */
+	if (info->ecclayout->oobavail)
+		oob_num = (ops->ooblen +
+			info->ecclayout->oobavail - 1) / info->ecclayout->oobavail;
+	else
+		oob_num = 0;
+
+	count = 0;
+
+	main_left = ops->len;
+	main_ok = 0;
+	main_offset = page_offset;
+
+	oob_left = ops->ooblen;
+	oob_ok = 0;
+
+	while (1) {
+		if (count < page_num || count < oob_num)
+			memset(chip->buf, 0xFF, info->page_size);
+		else
+			break;
+
+		if (count < page_num && ops->datbuf) {
+			int size;
+
+			if ((main_offset + main_left) < info->page_main_size)
+				size = main_left;
+			else
+				size = info->page_main_size - main_offset;
+
+			memcpy(chip->buf, ops->datbuf + main_ok, size);
+
+			main_ok += size;
+			main_left -= size;
+			main_offset = 0;
+
+#ifdef CONFIG_MTD_SPINAND_SWECC
+		spinand_calculate_ecc(mtd);
+#endif
+		}
+
+		if (count < oob_num && ops->oobbuf && chip->oobbuf) {
+			int size;
+			int offset, len, temp;
+
+			memset(chip->oobbuf, 0xFF, info->ecclayout->oobavail);
+
+			if (oob_left < info->ecclayout->oobavail)
+				size = oob_left;
+			else
+				size = info->ecclayout->oobavail;
+
+			memcpy(chip->oobbuf, ops->oobbuf + oob_ok, size);
+
+			oob_ok += size;
+			oob_left -= size;
+
+			/* repack oob to spare */
+			temp = 0;
+			offset = info->ecclayout->oobfree[0].offset;
+			len = info->ecclayout->oobfree[0].length;
+			memcpy(chip->buf + info->page_main_size + offset,
+					chip->oobbuf + temp, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[1].offset;
+			len = info->ecclayout->oobfree[1].length;
+			memcpy(chip->buf + info->page_main_size + offset,
+					chip->oobbuf + temp, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[2].offset;
+			len = info->ecclayout->oobfree[2].length;
+			memcpy(chip->buf + info->page_main_size + offset,
+					chip->oobbuf + temp, len);
+
+			temp += len;
+			offset = info->ecclayout->oobfree[3].offset;
+			len = info->ecclayout->oobfree[3].length;
+			memcpy(chip->buf + info->page_main_size + offset,
+					chip->oobbuf + temp, len);
+		}
+
+		if (count < page_num || count < oob_num) {
+			retval = chip->program_page(spi_nand, info,
+				page_id + count, 0, info->page_size, chip->buf);
+			if (retval != 0) {
+				errcode = -1;
+				pr_err(KERN_INFO "spinand_write_ops: fail, page=%d!\n", page_id);
+
+				return errcode;
+			}
+		}
+
+		if (count < page_num && ops->datbuf)
+			ops->retlen = main_ok;
+
+		if (count < oob_num && ops->oobbuf && chip->oobbuf)
+			ops->oobretlen = oob_ok;
+
+		count++;
+	}
+	return errcode;
+}
+
+static int spinand_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct mtd_oob_ops ops = {0};
+	int ret;
+
+	/* Do not allow reads past end of device */
+	if ((from + len) > mtd->size)
+		return -EINVAL;
+
+	if (!len)
+		return 0;
+
+	spinand_get_device(mtd, FL_READING);
+
+	ops.len = len;
+	ops.datbuf = buf;
+
+	ret = spinand_read_ops(mtd, from, &ops);
+
+	*retlen = ops.retlen;
+
+	spinand_release_device(mtd);
+
+	return ret;
+}
+
+static int spinand_write(struct mtd_info *mtd, loff_t to, size_t len,
+	size_t *retlen, const u_char *buf)
+{
+	struct mtd_oob_ops ops = {0};
+	int ret;
+
+	/* Do not allow reads past end of device */
+	if ((to + len) > mtd->size)
+		return -EINVAL;
+	if (!len)
+		return 0;
+
+	spinand_get_device(mtd, FL_WRITING);
+
+	ops.len = len;
+	ops.datbuf = (uint8_t *)buf;
+
+	ret =  spinand_write_ops(mtd, to, &ops);
+
+	*retlen = ops.retlen;
+
+	spinand_release_device(mtd);
+
+	return ret;
+}
+
+static int spinand_read_oob(struct mtd_info *mtd, loff_t from,
+			struct mtd_oob_ops *ops)
+{
+	int ret;
+
+	spinand_get_device(mtd, FL_READING);
+
+	ret = spinand_read_ops(mtd, from, ops);
+
+	spinand_release_device(mtd);
+	return ret;
+}
+
+static int spinand_write_oob(struct mtd_info *mtd, loff_t to,
+			  struct mtd_oob_ops *ops)
+{
+	int ret;
+
+	spinand_get_device(mtd, FL_WRITING);
+
+	ret = spinand_write_ops(mtd, to, ops);
+
+	spinand_release_device(mtd);
+	return ret;
+}
+
+/**
+ * spinand_erase - [MTD Interface] erase block(s)
+ * @param mtd		MTD device structure
+ * @param instr		erase instruction
+ *
+ * Erase one ore more blocks
+ */
+static int spinand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spi_device *spi_nand = chip->spi_nand;
+	struct spinand_info *info = chip->info;
+	u16 block_id, block_num, count;
+	signed int retval = 0;
+	signed int errcode = 0;
+
+	pr_info("spinand_erase: start = 0x%012llx, len = %llu\n",
+	      (unsigned long long)instr->addr, (unsigned long long)instr->len);
+
+	/* check address align on block boundary */
+	if (instr->addr & (info->block_main_size - 1)) {
+		pr_err("spinand_erase: Unaligned address\n");
+		return -EINVAL;
+	}
+
+	if (instr->len & (info->block_main_size - 1)) {
+		pr_err("spinand_erase: ""Length not block aligned\n");
+		return -EINVAL;
+	}
+
+	/* Do not allow erase past end of device */
+	if ((instr->len + instr->addr) > info->usable_size) {
+		pr_err("spinand_erase: ""Erase past end of device\n");
+		return -EINVAL;
+	}
+
+	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+
+	/* Grab the lock and see if the device is available */
+	spinand_get_device(mtd, FL_ERASING);
+
+	block_id = instr->addr >> info->block_shift;
+	block_num = instr->len >> info->block_shift;
+	count = 0;
+
+	while (count < block_num) {
+		retval = chip->erase_block(spi_nand, info, block_id + count);
+
+		if (retval != 0) {
+			retval = chip->erase_block(spi_nand, info,
+					block_id + count);
+			if (retval != 0) {
+				pr_info(KERN_INFO "spinand_erase: fail, block=%d!\n",
+					block_id + count);
+				errcode = -1;
+			}
+		}
+		count++;
+	}
+
+	if (errcode == 0)
+		instr->state = MTD_ERASE_DONE;
+
+	/* Deselect and wake up anyone waiting on the device */
+	spinand_release_device(mtd);
+
+	/* Do call back function */
+	if (instr->callback)
+		instr->callback(instr);
+
+	return errcode;
+}
+
+/**
+ * spinand_sync - [MTD Interface] sync
+ * @param mtd		MTD device structure
+ *
+ * Sync is actually a wait for chip ready function
+ */
+static void spinand_sync(struct mtd_info *mtd)
+{
+	pr_debug("spinand_sync: called\n");
+
+	/* Grab the lock and see if the device is available */
+	spinand_get_device(mtd, FL_SYNCING);
+
+	/* Release it and go back */
+	spinand_release_device(mtd);
+}
+
+static int spinand_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spi_device *spi_nand = chip->spi_nand;
+	struct spinand_info *info = chip->info;
+	u16 block_id;
+	u8 is_bad = 0x00;
+	u8 ret = 0;
+
+	spinand_get_device(mtd, FL_READING);
+
+	block_id = ofs >> info->block_shift;
+
+	chip->read_page(spi_nand, info, block_id*info->page_num_per_block,
+				info->page_main_size, 1, &is_bad);
+
+	if (is_bad != 0xFF)
+		ret =  1;
+
+	spinand_release_device(mtd);
+
+	return ret;
+}
+
+/**
+ * spinand_block_markbad - [MTD Interface] Mark bad block
+ * @param mtd		MTD device structure
+ * @param ofs       Bad block number
+ */
+static int spinand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spi_device *spi_nand = chip->spi_nand;
+	struct spinand_info *info = chip->info;
+	u16 block_id;
+	u8 is_bad = 0x00;
+	u8 ret = 0;
+
+	spinand_get_device(mtd, FL_WRITING);
+
+	block_id = ofs >> info->block_shift;
+
+	chip->program_page(spi_nand, info, block_id*info->page_num_per_block,
+		info->page_main_size, 1, &is_bad);
+
+	spinand_release_device(mtd);
+
+	return ret;
+}
+
+
+/**
+ * spinand_suspend - [MTD Interface] Suspend the spinand flash
+ * @param mtd		MTD device structure
+ */
+static int spinand_suspend(struct mtd_info *mtd)
+{
+	return spinand_get_device(mtd, FL_PM_SUSPENDED);
+}
+
+/**
+ * spinand_resume - [MTD Interface] Resume the spinand flash
+ * @param mtd		MTD device structure
+ */
+static void spinand_resume(struct mtd_info *mtd)
+{
+	struct spinand_chip *this = mtd->priv;
+
+	if (this->state == FL_PM_SUSPENDED)
+		spinand_release_device(mtd);
+	else
+		pr_err(KERN_ERR "resume() called for the chip which is not" "in suspended state\n");
+}
+
+/**
+ * spinand_mtd - add MTD device with parameters
+ * @param mtd		MTD device structure
+ *
+ * Add MTD device with parameters.
+ */
+int spinand_mtd(struct mtd_info *mtd)
+{
+	struct spinand_chip *chip = mtd->priv;
+	struct spinand_info *info = chip->info;
+
+	chip->state = FL_READY;
+	init_waitqueue_head(&chip->wq);
+	spin_lock_init(&chip->chip_lock);
+
+	mtd->name = info->name;
+	mtd->size = info->usable_size;
+	mtd->erasesize = info->block_main_size;
+	mtd->writesize = info->page_main_size;
+	mtd->oobsize = info->page_spare_size;
+	mtd->owner = THIS_MODULE;
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+
+	mtd->ecclayout = info->ecclayout;
+
+	mtd->_erase = spinand_erase;
+	mtd->_point = NULL;
+	mtd->_unpoint = NULL;
+	mtd->_read = spinand_read;
+	mtd->_write = spinand_write;
+	mtd->_read_oob = spinand_read_oob;
+	mtd->_write_oob = spinand_write_oob;
+	mtd->_sync = spinand_sync;
+	mtd->_lock = NULL;
+	mtd->_unlock = NULL;
+	mtd->_suspend = spinand_suspend;
+	mtd->_resume = spinand_resume;
+	mtd->_block_isbad = spinand_block_isbad;
+	mtd->_block_markbad = spinand_block_markbad;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spinand_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Henry Pan<hspan at micron.com>");
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
new file mode 100644
index 0000000..3b8802a
--- /dev/null
+++ b/include/linux/mtd/spinand.h
@@ -0,0 +1,155 @@
+/*
+ *  linux/include/linux/mtd/spinand.h
+ *  Copyright (c) 2009-2010 Micron Technology, Inc.
+ *  This software is licensed under the terms of the GNU General Public
+ *  License version 2, as published by the Free Software Foundation, and
+ *  may be copied, distributed, and modified under those terms.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+/bin/bash: 4: command not found
+ *
+ *  based on nand.h
+ */
+#ifndef __LINUX_MTD_SPI_NAND_H
+#define __LINUX_MTD_SPI_NAND_H
+
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/mtd/mtd.h>
+
+/* cmd */
+#define CMD_READ				0x13
+#define CMD_READ_RDM			0x03
+#define CMD_PROG_PAGE_CLRCACHE	0x02
+#define CMD_PROG_PAGE			0x84
+#define CMD_PROG_PAGE_EXC		0x10
+#define CMD_ERASE_BLK			0xd8
+#define CMD_WR_ENABLE			0x06
+#define CMD_WR_DISABLE			0x04
+#define CMD_READ_ID			0x9f
+#define CMD_RESET				0xff
+#define CMD_READ_REG			0x0f
+#define CMD_WRITE_REG			0x1f
+
+/* feature/ status reg */
+#define REG_BLOCK_LOCK		0xa0
+#define REG_OTP				0xb0
+#define REG_STATUS			0xc0/* timing */
+
+/* status */
+#define STATUS_OIP_MASK		0x01
+#define STATUS_READY		(0 << 0)
+#define STATUS_BUSY			(1 << 0)
+
+#define STATUS_E_FAIL_MASK	0x04
+#define STATUS_E_FAIL		(1 << 2)
+
+#define STATUS_P_FAIL_MASK	0x08
+#define STATUS_P_FAIL		(1 << 3)
+
+#define STATUS_ECC_MASK		0x30
+#define STATUS_ECC_1BIT_CORRECTED	(1 << 4)
+#define STATUS_ECC_ERROR			(2 << 4)
+#define STATUS_ECC_RESERVED			(3 << 4)
+
+
+/*ECC enable defines*/
+#define OTP_ECC_MASK		0x10
+#define OTP_ECC_OFF			0
+#define OTP_ECC_ON			1
+
+#define ECC_DISABLED
+#define ECC_IN_NAND
+#define ECC_SOFT
+
+/* block lock */
+#define BL_ALL_LOCKED      0x38
+#define BL_1_2_LOCKED      0x30
+#define BL_1_4_LOCKED      0x28
+#define BL_1_8_LOCKED      0x20
+#define BL_1_16_LOCKED     0x18
+#define BL_1_32_LOCKED     0x10
+#define BL_1_64_LOCKED     0x08
+#define BL_ALL_UNLOCKED    0
+
+struct spinand_info {
+	u8		mid;
+	u8		did;
+	char		*name;
+	u64		nand_size;
+	u64		usable_size;
+
+	u32		block_size;
+	u32		block_main_size;
+	/*u32		block_spare_size; */
+	u16		block_num_per_chip;
+	u16		page_size;
+	u16		page_main_size;
+	u16		page_spare_size;
+	u16		page_num_per_block;
+	u8		block_shift;
+	u32		block_mask;
+	u8		page_shift;
+	u16		page_mask;
+
+	struct nand_ecclayout *ecclayout;
+};
+
+typedef enum {
+	FL_READY,
+	FL_READING,
+	FL_WRITING,
+	FL_ERASING,
+	FL_SYNCING,
+	FL_LOCKING,
+	FL_RESETING,
+	FL_OTPING,
+	FL_PM_SUSPENDED,
+} spinand_state_t;
+
+struct spinand_chip { /* used for multi chip */
+	spinlock_t		chip_lock;
+	wait_queue_head_t wq;
+	spinand_state_t	state;
+	struct spi_device	*spi_nand;
+	struct spinand_info *info;
+	/*struct mtd_info	*mtd; */
+
+	int (*reset) (struct spi_device *spi_nand);
+	int (*read_id) (struct spi_device *spi_nand, u8 *id);
+	int (*read_page) (struct spi_device *spi_nand,
+		struct spinand_info *info, u16 page_id, u16 offset,
+		u16 len, u8 *rbuf);
+	int (*program_page) (struct spi_device *spi_nand,
+		struct spinand_info *info, u16 page_id, u16 offset,
+		u16 len, u8 *wbuf);
+	int (*erase_block) (struct spi_device *spi_nand,
+		struct spinand_info *info, u16 block_id);
+
+	u8 *buf;
+	u8 *oobbuf; /* temp buffer */
+
+#ifdef CONFIG_MTD_SPINAND_SWECC
+	u8 ecc_calc[12];
+	u8 ecc_code[12];
+#endif
+};
+
+struct spinand_cmd {
+	u8 cmd;
+	unsigned n_addr;
+	u8 addr[3];
+	unsigned n_dummy;
+	unsigned n_tx;
+	u8 *tx_buf;
+	unsigned n_rx;
+	u8 *rx_buf;
+};
+
+extern int spinand_mtd(struct mtd_info *mtd);
+extern void spinand_mtd_release(struct mtd_info *mtd);
+
+#endif
-- 
1.7.1



From sourav.poddar at ti.com  Wed Jun 26 03:41:11 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Wed, 26 Jun 2013 13:11:11 +0530
Subject: [PATCH 2/3] drivers: spi: Add qspi flash controller
In-Reply-To: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
Message-ID: <1372232472-2641-3-git-send-email-sourav.poddar@ti.com>

The patch add basic support for the quad spi controller.

QSPI is a kind of spi module that allows single,
dual and quad read access to external spi devices. The module
has a memory mapped interface which provide direct interface
for accessing data form external spi devices.

The patch will configure controller clocks, device control
register and for defining low level transfer apis which
will be used by the spi framework to transfer data to
the slave spi device(flash in this case).

Signed-off-by: Sourav Poddar <sourav.poddar at ti.com>
---
 drivers/spi/Kconfig   |    6 +
 drivers/spi/Makefile  |    1 +
 drivers/spi/ti-qspi.c |  352 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 359 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/ti-qspi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 92a9345..29a363b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -285,6 +285,12 @@ config SPI_OMAP24XX
 	  SPI master controller for OMAP24XX and later Multichannel SPI
 	  (McSPI) modules.
 
+config QSPI_DRA7xxx
+	tristate "DRA7xxx QSPI controller support"
+	depends on ARCH_OMAP2PLUS
+	help
+	  QSPI master controller for DRA7xxx used for flash devices.
+
 config SPI_OMAP_100K
 	tristate "OMAP SPI 100K"
 	depends on ARCH_OMAP850 || ARCH_OMAP730
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 33f9c09..ea14eff 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SPI_OCTEON)		+= spi-octeon.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= spi-omap-uwire.o
 obj-$(CONFIG_SPI_OMAP_100K)		+= spi-omap-100k.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= spi-omap2-mcspi.o
+obj-$(CONFIG_QSPI_DRA7xxx)              += ti-qspi.o
 obj-$(CONFIG_SPI_ORION)			+= spi-orion.o
 obj-$(CONFIG_SPI_PL022)			+= spi-pl022.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
diff --git a/drivers/spi/ti-qspi.c b/drivers/spi/ti-qspi.c
new file mode 100644
index 0000000..b33646a
--- /dev/null
+++ b/drivers/spi/ti-qspi.c
@@ -0,0 +1,352 @@
+/*
+ * TI QSPI driver
+ *
+ * Copyright (C) 2013, Texas Instruments, Incorporated
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/spi/spi.h>
+
+struct dra7xxx_qspi {
+	struct spi_master	*master;
+	void __iomem            *base;
+	int device_type;
+	struct device           *dev;
+	u32 spi_max_frequency;
+	u32 cmd;
+	u32 dc;
+};
+
+#define QSPI_PID			(0x0)
+#define QSPI_SYSCONFIG			(0x10)
+#define QSPI_INTR_STATUS_RAW_SET	(0x20)
+#define QSPI_INTR_STATUS_ENABLED_CLEAR	(0x24)
+#define QSPI_INTR_ENABLE_SET_REG	(0x28)
+#define QSPI_INTR_ENABLE_CLEAR_REG	(0x2c)
+#define QSPI_SPI_CLOCK_CNTRL_REG	(0x40)
+#define QSPI_SPI_DC_REG			(0x44)
+#define QSPI_SPI_CMD_REG		(0x48)
+#define QSPI_SPI_STATUS_REG		(0x4c)
+#define QSPI_SPI_DATA_REG		(0x50)
+#define QSPI_SPI_SETUP0_REG		(0x54)
+#define QSPI_SPI_SWITCH_REG		(0x64)
+#define QSPI_SPI_SETUP1_REG		(0x58)
+#define QSPI_SPI_SETUP2_REG		(0x5c)
+#define QSPI_SPI_SETUP3_REG		(0x60)
+#define QSPI_SPI_DATA_REG_1		(0x68)
+#define QSPI_SPI_DATA_REG_2		(0x6c)
+#define QSPI_SPI_DATA_REG_3		(0x70)
+
+#define QSPI_TIMEOUT			2000000
+
+#define QSPI_FCLK			192000000
+
+/* Clock Control */
+#define QSPI_CLK_EN			(1 << 31)
+#define QSPI_CLK_DIV_MAX		0xffff
+
+/* Command */
+#define QSPI_EN_CS(n)			(n << 28)
+#define QSPI_WLEN(n)			((n-1) << 19)
+#define QSPI_3_PIN			(1 << 18)
+#define QSPI_RD_SNGL			(1 << 16)
+#define QSPI_WR_SNGL			(2 << 16)
+#define QSPI_RD_QUAD			(7 << 16)
+#define QSPI_INVAL			(4 << 16)
+
+/* Device Control */
+#define QSPI_DD(m, n)			(m << (3 + n*8))
+#define QSPI_CKPHA(n)			(1 << (2 + n*8))
+#define QSPI_CSPOL(n)			(1 << (1 + n*8))
+#define QSPI_CKPOL(n)			(1 << (n*8))
+
+/* Status */
+#define QSPI_WC				(1 << 1)
+#define QSPI_BUSY			(1 << 0)
+#define QSPI_WC_BUSY			(QSPI_WC | QSPI_BUSY)
+#define QSPI_XFER_DONE			QSPI_WC
+
+#define XFER_END			0x01
+
+#define SPI_AUTOSUSPEND_TIMEOUT         2000
+
+static inline unsigned long dra7xxx_readl(struct dra7xxx_qspi *qspi,
+		unsigned long reg)
+{
+	return readl(qspi->base + reg);
+}
+
+static inline void dra7xxx_writel(struct dra7xxx_qspi *qspi,
+		unsigned long val, unsigned long reg)
+{
+	writel(val, qspi->base + reg);
+}
+
+static int dra7xxx_qspi_setup(struct spi_device *spi)
+{
+	struct dra7xxx_qspi	*qspi =
+			spi_master_get_devdata(spi->master);
+
+	int clk_div;
+
+	if (!qspi->spi_max_frequency)
+		clk_div = 0;
+	else
+		clk_div = (QSPI_FCLK / qspi->spi_max_frequency) - 1;
+
+	pr_debug("%s: hz: %d, clock divider %d\n", __func__,
+			qspi->spi_max_frequency, clk_div);
+
+	pm_runtime_get_sync(qspi->dev);
+
+	/* disable SCLK */
+	dra7xxx_writel(qspi, dra7xxx_readl(qspi, QSPI_SPI_CLOCK_CNTRL_REG)
+			& ~QSPI_CLK_EN, QSPI_SPI_CLOCK_CNTRL_REG);
+
+	if (clk_div < 0) {
+		pr_debug("%s: clock divider < 0, using /1 divider\n", __func__);
+		clk_div = 0;
+	}
+
+	if (clk_div > QSPI_CLK_DIV_MAX) {
+		pr_debug("%s: clock divider >%d , using /%d divider\n",
+			__func__, QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
+		clk_div = QSPI_CLK_DIV_MAX;
+	}
+
+	/* enable SCLK */
+	dra7xxx_writel(qspi, QSPI_CLK_EN | clk_div, QSPI_SPI_CLOCK_CNTRL_REG);
+
+	pm_runtime_mark_last_busy(qspi->dev);
+	pm_runtime_put_autosuspend(qspi->dev);
+
+	pr_debug("%s: spi_clock_cntrl %ld\n", __func__,
+		dra7xxx_readl(qspi, QSPI_SPI_CLOCK_CNTRL_REG));
+
+	return 0;
+}
+
+static int dra7xxx_qspi_prepare_xfer(struct spi_master *master)
+{
+	return 0;
+}
+
+static int dra7xxx_qspi_unprepare_xfer(struct spi_master *master)
+{
+	return 0;
+}
+
+static int qspi_transfer_msg(struct dra7xxx_qspi *qspi, unsigned count,
+			const u8 *txbuf, u8 *rxbuf, bool flags)
+{
+	uint status;
+	int timeout;
+
+	pm_runtime_get_sync(qspi->dev);
+
+	while (count--) {
+		if (txbuf) {
+			pr_debug("tx cmd %08x dc %08x data %02x\n",
+				qspi->cmd | QSPI_WR_SNGL, qspi->dc, *txbuf);
+			dra7xxx_writel(qspi, *txbuf++, QSPI_SPI_DATA_REG);
+			dra7xxx_writel(qspi, qspi->dc, QSPI_SPI_DC_REG);
+			dra7xxx_writel(qspi, qspi->cmd | QSPI_WR_SNGL,
+					QSPI_SPI_CMD_REG);
+			status = dra7xxx_readl(qspi, QSPI_SPI_STATUS_REG);
+			timeout = QSPI_TIMEOUT;
+			while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
+				if (--timeout < 0) {
+					pr_debug("QSPI tx timed out\n");
+					return -1;
+				}
+				status = dra7xxx_readl(qspi, QSPI_SPI_STATUS_REG);
+			}
+			pr_debug("tx done, status %08x\n", status);
+		}
+		if (rxbuf) {
+			pr_debug("rx cmd %08x dc %08x\n",
+				qspi->cmd | QSPI_RD_SNGL, qspi->dc);
+			dra7xxx_writel(qspi, qspi->dc, QSPI_SPI_DC_REG);
+			dra7xxx_writel(qspi, qspi->cmd | QSPI_RD_SNGL,
+					QSPI_SPI_CMD_REG);
+			status = dra7xxx_readl(qspi, QSPI_SPI_STATUS_REG);
+			timeout = QSPI_TIMEOUT;
+			while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
+				if (--timeout < 0) {
+					pr_debug("QSPI rx timed out\n");
+					return -1;
+				}
+				status = dra7xxx_readl(qspi, QSPI_SPI_STATUS_REG);
+			}
+			*rxbuf++ = dra7xxx_readl(qspi, QSPI_SPI_DATA_REG);
+			pr_debug("rx done, status %08x, read %02x\n",
+				status, *(rxbuf-1));
+		}
+	}
+
+	if (flags & XFER_END)
+		dra7xxx_writel(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
+
+	pm_runtime_mark_last_busy(qspi->dev);
+	pm_runtime_put_autosuspend(qspi->dev);
+
+	return 0;
+}
+
+static int dra7xxx_qspi_start_transfer_one(struct spi_master *master,
+		struct spi_message *m)
+{
+	struct dra7xxx_qspi *qspi = spi_master_get_devdata(master);
+	struct spi_device *spi = m->spi;
+	struct spi_transfer *t;
+	int status = 0;
+	int flags = 0;
+
+	/* setup command reg */
+	qspi->cmd = 0;
+	qspi->cmd |= QSPI_WLEN(8);
+	qspi->cmd |= QSPI_EN_CS(0);
+	qspi->cmd |= 0xfff;
+
+	/* setup device control reg */
+	qspi->dc = 0;
+
+	if (spi->mode & SPI_CPHA)
+		qspi->dc |= QSPI_CKPHA(0);
+	if (spi->mode & SPI_CPOL)
+		qspi->dc |= QSPI_CKPOL(0);
+	if (spi->mode & SPI_CS_HIGH)
+		qspi->dc |= QSPI_CSPOL(0);
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (list_is_last(&t->transfer_list, &m->transfers))
+			flags = XFER_END;
+
+		qspi_transfer_msg(qspi, t->len, t->tx_buf,
+			t->rx_buf, flags);
+
+		m->actual_length += t->len;
+	}
+	m->status = status;
+	spi_finalize_current_message(master);
+
+	return status;
+}
+
+static int dra7xxx_qspi_probe(struct platform_device *pdev)
+{
+	struct  dra7xxx_qspi *qspi;
+	struct spi_master *master;
+	struct resource         *r;
+	struct device_node *np = pdev->dev.of_node;
+	u32 max_freq;
+	int ret;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
+	if (!master)
+		return -ENOMEM;
+
+	master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+	master->num_chipselect = 1;
+	master->bus_num = -1;
+	master->setup = dra7xxx_qspi_setup;
+	master->prepare_transfer_hardware = dra7xxx_qspi_prepare_xfer;
+	master->transfer_one_message = dra7xxx_qspi_start_transfer_one;
+	master->unprepare_transfer_hardware = dra7xxx_qspi_unprepare_xfer;
+	master->dev.of_node = pdev->dev.of_node;
+
+	dev_set_drvdata(&pdev->dev, master);
+
+	qspi = spi_master_get_devdata(master);
+	qspi->master = master;
+	qspi->dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		ret = -ENODEV;
+		goto free_master;
+	}
+
+	qspi->base = devm_request_and_ioremap(&pdev->dev, r);
+	if (!qspi->base) {
+		dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
+		ret = -ENOMEM;
+		goto free_master;
+	}
+
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
+	pm_runtime_enable(&pdev->dev);
+
+	if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
+		qspi->spi_max_frequency = max_freq;
+
+	ret = spi_register_master(master);
+	if (ret)
+		goto free_master;
+
+	return ret;
+
+free_master:
+	spi_master_put(master);
+	return ret;
+}
+
+static int dra7xxx_qspi_remove(struct platform_device *pdev)
+{
+	struct  dra7xxx_qspi *qspi = platform_get_drvdata(pdev);
+
+	spi_unregister_master(qspi->master);
+
+	return 0;
+}
+
+static const struct of_device_id dra7xxx_qspi_match[] = {
+	{.compatible = "ti,dra7xxx-qspi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dra7xxx_qspi_match);
+
+static struct platform_driver dra7xxx_qspi_driver = {
+	.probe	= dra7xxx_qspi_probe,
+	.remove	= dra7xxx_qspi_remove,
+	.driver = {
+		.name	= "ti,dra7xxx-qspi",
+		.owner	= THIS_MODULE,
+		.of_match_table = dra7xxx_qspi_match,
+	}
+};
+
+module_platform_driver(dra7xxx_qspi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI QSPI controller driver");
-- 
1.7.1



From sourav.poddar at ti.com  Wed Jun 26 03:41:12 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Wed, 26 Jun 2013 13:11:12 +0530
Subject: [PATCH 3/3] drivers: mtd: spinand: Add qspi spansion flash controller
In-Reply-To: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
Message-ID: <1372232472-2641-4-git-send-email-sourav.poddar@ti.com>

The patch adds support for spansion s25fl256s spi flash controller.
Currently, the patch supports only SPI based transaction.

As, the qspi to which flash is attached supports memory mapped interface,
support will be added in future for memory mapped transactions also.

This driver gets attached to the generic spinand mtd framework proposed in the
first patch of the series.

Signed-off-by: Sourav Poddar <sourav.poddar at ti.com>
---
 drivers/mtd/spinand/Kconfig         |    7 +
 drivers/mtd/spinand/Makefile        |    2 +-
 drivers/mtd/spinand/ti-qspi-flash.c |  373 +++++++++++++++++++++++++++++++++++
 3 files changed, 381 insertions(+), 1 deletions(-)
 create mode 100644 drivers/mtd/spinand/ti-qspi-flash.c

diff --git a/drivers/mtd/spinand/Kconfig b/drivers/mtd/spinand/Kconfig
index 38c739f..1342de3 100644
--- a/drivers/mtd/spinand/Kconfig
+++ b/drivers/mtd/spinand/Kconfig
@@ -16,6 +16,13 @@ config MTD_SPINAND_ONDIEECC
 	help
 	 Internel ECC
 
+config MTD_S25FL256S
+	tristate "Support spansion memory mapped SPI Flash chips"
+	depends on SPI_MASTER
+	help
+	  This enables access to spansion QSPI flash chips, which used
+	  memory mapped interface used for program and data storage.
+
 config MTD_SPINAND_SWECC
 	bool "Use software ECC"
 	depends on MTD_NAND
diff --git a/drivers/mtd/spinand/Makefile b/drivers/mtd/spinand/Makefile
index 355e726..8ad0dd5 100644
--- a/drivers/mtd/spinand/Makefile
+++ b/drivers/mtd/spinand/Makefile
@@ -5,6 +5,6 @@
 # Core functionality.
 obj-$(CONFIG_MTD_SPINAND)		+= spinand.o
 
-spinand-objs := spinand_mtd.o spinand_lld.o
+spinand-objs := spinand_mtd.o spinand_lld.o ti-qspi-flash.o
 
 
diff --git a/drivers/mtd/spinand/ti-qspi-flash.c b/drivers/mtd/spinand/ti-qspi-flash.c
new file mode 100644
index 0000000..dfa6235
--- /dev/null
+++ b/drivers/mtd/spinand/ti-qspi-flash.c
@@ -0,0 +1,373 @@
+/*
+ * MTD SPI driver for spansion s25fl256s (and similar) serial flash chips
+ *
+ * Author: Sourav Poddar, sourav.poddar at ti.com
+ *
+ * Copyright (c) 2013, Texas Instruments.
+ *
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/math64.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mod_devicetable.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_platform.h>
+
+#include <linux/spi/spi.h>
+#include <linux/mtd/spinand.h>
+
+#define	CMD_OPCODE_RDSR		0x05    /* Read status register */
+#define CMD_OPCODE_FAST_READ	0x0b	/* Fast Read */
+#define	MAX_READY_WAIT_JIFFIES	(40 * HZ) /* M25P16 specs 40s max chip erase */
+
+#define	SR_WIP		1       /* Write in progress */
+#define	SR_WEL		2       /* Write enable latch */
+
+static u16	addr_width;
+bool	fast_read;
+
+static struct nand_ecclayout spinand_oob_0 = {
+	.eccbytes = 0,
+	.eccpos = {},
+	.oobavail = 0,
+	.oobfree = {
+		{.offset = 0,
+		.length = 0}, }
+};
+
+/*
+ * Read the status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+*/
+static int read_sr(struct spi_device *spi_nand)
+{
+	ssize_t retval;
+	u8 val;
+	u8 code	=	CMD_OPCODE_RDSR;
+
+	retval = spi_write_then_read(spi_nand, &code, 1, &val, 1);
+
+	if (retval < 0) {
+		dev_info(&spi_nand->dev, "error %d reading SR\n",
+			(int) retval);
+		return retval;
+	}
+
+	return val;
+}
+
+/*
+ * Set write enable latch with Write Enable command.
+ * Returns negative if error occurred.
+*/
+static inline int write_enable(struct spi_device *spi_nand)
+{
+	u8	code = CMD_WR_ENABLE;
+
+	return spi_write_then_read(spi_nand, &code, 1, NULL, 0);
+}
+
+/*
+ * Send write disble instruction to the chip.
+*/
+static inline int write_disable(struct spi_device *spi_nand)
+{
+	u8	code = CMD_WR_DISABLE;
+
+	return spi_write_then_read(spi_nand, &code, 1, NULL, 0);
+}
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+*/
+static int wait_till_ready(struct spi_device *spi_nand)
+{
+	unsigned long deadline;
+	int sr;
+
+	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+
+	do {
+		sr = read_sr(spi_nand);
+		if (sr < 0)
+			return -1;
+		else if (!(sr & SR_WIP))
+			break;
+
+		cond_resched();
+	} while (!time_after_eq(jiffies, deadline));
+
+	if ((sr & SR_WIP) == 0)
+		return 0;
+
+	return -1;
+}
+
+static inline int spinand_read_id(struct spi_device *spi_nand, u8 *id)
+{
+	u8      code = CMD_READ_ID;
+
+	return  spi_write_then_read(spi_nand, &code, 1, id, sizeof(id));
+}
+
+static void s25fl_addr2cmd(struct spi_device *spi_nand,
+		unsigned int addr, u8 *cmd)
+{
+	/* opcode is in cmd[0] */
+	cmd[1] = addr >> (addr_width * 8 -  8);
+	cmd[2] = addr >> (addr_width * 8 - 16);
+	cmd[3] = addr >> (addr_width * 8 - 24);
+}
+
+static int s25fl_cmdsz(struct  spi_device *spi_nand)
+{
+	return 1 + addr_width;
+}
+
+static int spinand_erase_block(struct spi_device *spi_nand,
+		struct spinand_info *info, u16 block_id)
+{
+	unsigned int offset;
+	u8 cmd[4];
+	uint8_t opcode;
+
+	offset = block_id * info->block_size;
+
+	/* Wait until finished previous write command. */
+	if (wait_till_ready(spi_nand))
+		return 1;
+
+	/* Send write enable, then erase commands. */
+	write_enable(spi_nand);
+
+	/* Set up command buffer. */
+	opcode = CMD_ERASE_BLK;
+	cmd[0] = opcode;
+	s25fl_addr2cmd(spi_nand, offset, cmd);
+
+	spi_write(spi_nand, cmd, s25fl_cmdsz(spi_nand));
+
+	return 0;
+}
+
+static int spinand_read_page(struct spi_device *spi_nand,
+	struct spinand_info *info, u16 page_id, u16 offset, u16 len, u8 *rbuf)
+{
+	struct spi_transfer t[2];
+	struct spi_message m;
+	uint8_t opcode;
+	u8 cmd[4];
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = s25fl_cmdsz(spi_nand);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = rbuf;
+	t[1].len = len;
+	spi_message_add_tail(&t[1], &m);
+
+	/* Wait till previous write/erase is done. */
+	if (wait_till_ready(spi_nand))
+		return 1;
+
+	/* Set up the write data buffer. */
+	opcode = fast_read ? CMD_OPCODE_FAST_READ : CMD_READ_RDM;
+	cmd[0] = opcode;
+
+	s25fl_addr2cmd(spi_nand, offset, cmd);
+
+	spi_sync(spi_nand, &m);
+
+	return 0;
+}
+
+static int spinand_program_page(struct spi_device *spi_nand,
+	struct spinand_info *info, u16 page_id, u16 offset, u16 len, u8 *wbuf)
+{
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u8 cmd[4];
+
+	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&spi_nand->dev),
+			__func__, (u32)offset, len);
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = 4;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = wbuf;
+        t[0].len = len;
+	spi_message_add_tail(&t[1], &m);
+
+	write_enable(spi_nand);
+
+	/* Wait until finished previous write command. */
+	if (wait_till_ready(spi_nand))
+		return 1;
+
+	/* Set up the opcode in the write buffer. */
+	cmd[0] = CMD_PROG_PAGE_CLRCACHE;
+	s25fl_addr2cmd(spi_nand, offset, cmd);
+
+	spi_sync(spi_nand, &m);
+
+	return 0;
+}
+
+static int spinand_get_info(struct spi_device *spi_nand,
+		struct spinand_info *info, u8 *id)
+{
+	if (id[0] == 0x01 && id[1] == 0x02) {
+		info->mid = id[0];
+		info->did = id[1];
+		info->name = "S25FL256S";
+		info->nand_size = (1024 * 32 * 1024);
+		info->page_size = 256;
+		info->page_main_size = 256;
+		info->page_spare_size = info->page_size - info->page_main_size;
+		info->block_size = (1024 * 64);
+		info->page_num_per_block = info->block_size / info->page_size;
+		info->block_main_size = info->page_main_size *
+						info->page_num_per_block;
+		info->usable_size = (1024 * 30 * 1024);
+		info->block_num_per_chip = info->nand_size / info->block_size;
+		info->block_shift = 16;
+		info->block_mask = info->block_size - 1;
+		info->page_shift = 8;
+		info->page_mask = info->page_size - 1;
+		info->ecclayout = &spinand_oob_0;
+	}
+	return 0;
+}
+
+static int spinand_probe(struct spi_device *spi)
+{
+	ssize_t retval;
+	struct mtd_info *mtd;
+	struct spinand_chip *chip;
+	struct spinand_info *info;
+	struct mtd_part_parser_data     ppdata;
+	struct device_node __maybe_unused *np = spi->dev.of_node;
+
+	u8 id[2] = {0};
+
+	retval = spinand_read_id(spi, (u8 *)&id);
+	if (id[0] == 0 && id[1] == 0) {
+		pr_err(KERN_ERR "SPINAND: read id error! 0x%02x, 0x%02x!\n",
+			id[0], id[1]);
+		return 0;
+	}
+
+	info  = kzalloc(sizeof(struct spinand_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if (np && of_property_read_bool(np, "s25fl,fast-read"))
+		fast_read = true;
+	if (np && of_property_read_bool(np, "s25fl,three-byte"))
+		addr_width = 3;
+	else
+		addr_width = 4;
+
+	ppdata.of_node = spi->dev.of_node;
+
+	retval = spinand_get_info(spi, info, (u8 *)&id);
+
+	chip  = kzalloc(sizeof(struct spinand_chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->spi_nand = spi;
+	chip->info = info;
+	chip->read_id = spinand_read_id;
+	chip->read_page = spinand_read_page;
+	chip->program_page = spinand_program_page;
+	chip->erase_block = spinand_erase_block;
+	chip->buf = kzalloc(info->page_size, GFP_KERNEL);
+	if (!chip->buf)
+		return -ENOMEM;
+
+	chip->oobbuf = kzalloc(info->ecclayout->oobavail, GFP_KERNEL);
+	if (!chip->oobbuf)
+		return -ENOMEM;
+
+	mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
+	if (!mtd)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, mtd);
+
+	mtd->priv = chip;
+
+	retval = spinand_mtd(mtd);
+
+	return mtd_device_parse_register(mtd, NULL, &ppdata,
+			NULL, 1);
+}
+
+/*
+ *spinand_remove--Remove the device driver
+ * @spi: the spi device.
+*/
+static int spinand_remove(struct spi_device *spi)
+{
+	struct mtd_info *mtd;
+	struct spinand_chip *chip;
+
+	mtd = dev_get_drvdata(&spi->dev);
+
+	mtd_device_unregister(mtd);
+
+	chip = mtd->priv;
+
+	kfree(chip->info);
+	kfree(chip->buf);
+	kfree(chip->oobbuf);
+	kfree(chip);
+	kfree(mtd);
+
+	return 0;
+}
+
+static const struct of_device_id s25fl256s_dt_ids[] = {
+	{ .compatible = "ti, s25fl256s"},
+	{ /* sentinel */ },
+};
+
+static struct spi_driver spinand_driver = {
+	.driver = {
+		.name	= "s25fl256s",
+		.bus            = &spi_bus_type,
+		.owner	= THIS_MODULE,
+		.of_match_table = s25fl256s_dt_ids,
+	},
+	.probe	= spinand_probe,
+	.remove	= spinand_remove,
+};
+module_spi_driver(spinand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sourav Poddar");
+MODULE_DESCRIPTION("MTD SPI driver for spansion flash chips");
-- 
1.7.1



From kamlakant.patel at broadcom.com  Wed Jun 26 11:22:44 2013
From: kamlakant.patel at broadcom.com (Kamlakant Patel)
Date: Wed, 26 Jun 2013 20:52:44 +0530
Subject: [PATCH 1/3] drivers: mtd: spinand: Add generic spinand
 frameowrk and micron driver.
In-Reply-To: <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
 <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>
Message-ID: <20130626152243.GA9414@kpatel.netlogicmircro.com>

On Wed, Jun 26, 2013 at 01:11:10PM +0530, Sourav Poddar wrote:
> From: Mona Anonuevo <manonuevo at micron.com>
> 
> This patch adds support for a generic spinand framework(spinand_mtd.c).
> This frameowrk can be used for other spi based flash devices also. The idea
> is to have a common model under drivers/mtd, as also present for other no spi
> devices(there is a generic framework and device part simply attaches itself to it.)
> 
> The generic frework will be used later by me for a SPI based spansion S25FL256 device.
> The patch also contains a micron driver attaching itself to generic framework.
> 
> Signed-off-by: Mona Anonuevo <manonuevo at micron.com>
> Signed-off-by: Tuan Nguyen <tqnguyen at micron.com>
> Signed-off-by: Sourav Poddar <sourav.poddar at ti.com>
> ----
> [I picked this as a standalone patch, can split it into generic and device part
> based on community feedback.]
> 
>  drivers/mtd/Kconfig               |    2 +
>  drivers/mtd/Makefile              |    2 +
>  drivers/mtd/spinand/Kconfig       |   24 ++
>  drivers/mtd/spinand/Makefile      |   10 +
>  drivers/mtd/spinand/spinand_lld.c |  776 +++++++++++++++++++++++++++++++++++++
>  drivers/mtd/spinand/spinand_mtd.c |  690 +++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h       |  155 ++++++++
>  7 files changed, 1659 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mtd/spinand/Kconfig
>  create mode 100644 drivers/mtd/spinand/Makefile
>  create mode 100644 drivers/mtd/spinand/spinand_lld.c
>  create mode 100644 drivers/mtd/spinand/spinand_mtd.c
>  create mode 100644 include/linux/mtd/spinand.h
> 

I am working on Micron SPINAND(Micron MT29F1G01ZACH). I tried this patch, but it's not working.
It is throwing following error message while mounting:
[  260.232000] jffs2: cannot read OOB for EB at 00000000, requested 8 bytes, read 0 bytes, error -22
mount: mounting /dev/mtdblock5 on /mnt/ failed: Input/output error

I am working on it to fix into the driver, will send an updated patch with the fix.

Thanks,
Kamlakant Patel



From florian at openwrt.org  Wed Jun 26 10:15:56 2013
From: florian at openwrt.org (Florian Fainelli)
Date: Wed, 26 Jun 2013 15:15:56 +0100
Subject: [PATCH 1/3] drivers: mtd: spinand: Add generic spinand frameowrk
 and micron driver.
In-Reply-To: <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
 <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>
Message-ID: <CAGVrzcY6Writ9Ehs=tiumjfDinETgS_kL5C02eZtKG5ENaWGfQ@mail.gmail.com>

Hello,

2013/6/26 Sourav Poddar <sourav.poddar at ti.com>:
> From: Mona Anonuevo <manonuevo at micron.com>
>
> This patch adds support for a generic spinand framework(spinand_mtd.c).
> This frameowrk can be used for other spi based flash devices also. The idea
> is to have a common model under drivers/mtd, as also present for other no spi
> devices(there is a generic framework and device part simply attaches itself to it.)
>
> The generic frework will be used later by me for a SPI based spansion S25FL256 device.
> The patch also contains a micron driver attaching itself to generic framework.

Some general comments below, I do not have any SPI NAND devices, just
reading through the code.

> +
> +config MTD_SPINAND_ONDIEECC
> +       bool "Use SPINAND internal ECC"
> +       help
> +        Internel ECC
> +
> +config MTD_SPINAND_SWECC
> +       bool "Use software ECC"
> +       depends on MTD_NAND
> +       help
> +        software ECC

Cannot both of these be somehow detected by the identification bytes?
Or maybe explicitely specified in an identification table?

> +#define mu_spi_nand_driver_version "Beagle-MTD_01.00_Linux2.6.33_20100507"

You probably want to remove this.

> +#define SPI_NAND_MICRON_DRIVER_KEY 0x1233567

Ditto.

> +
> +/****************************************************************************/
> +
> +/**
> +   OOB area specification layout:  Total 32 available free bytes.
> +*/
> +static struct nand_ecclayout spinand_oob_64 = {
> +       .eccbytes = 24,
> +       .eccpos = {
> +                  1, 2, 3, 4, 5, 6,
> +                  17, 18, 19, 20, 21, 22,
> +                  33, 34, 35, 36, 37, 38,
> +                  49, 50, 51, 52, 53, 54, },
> +       .oobavail = 32,
> +       .oobfree = {
> +               {.offset = 8,
> +                .length = 8},
> +               {.offset = 24,
> +                .length = 8},
> +               {.offset = 40,
> +                .length = 8},
> +               {.offset = 56,
> +                .length = 8}, }
> +};

This should probably be per-device, or at best supplied by platform data?

> +/**
> + * spinand_cmd - to process a command to send to the SPI Nand
> + *
> + * Description:
> + *    Set up the command buffer to send to the SPI controller.
> + *    The command buffer has to initized to 0
> + */
> +int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
> +{
> +       int                                     ret;
> +       struct spi_message      message;
> +       struct spi_transfer             x[4];
> +       u8 dummy = 0xff;
> +
> +       spi_message_init(&message);
> +       memset(x, 0, sizeof(x));
> +
> +       x[0].len = 1;
> +       x[0].tx_buf = &cmd->cmd;
> +       spi_message_add_tail(&x[0], &message);
> +
> +       if (cmd->n_addr) {
> +               x[1].len = cmd->n_addr;
> +               x[1].tx_buf = cmd->addr;
> +               spi_message_add_tail(&x[1], &message);
> +       }
> +
> +       if (cmd->n_dummy) {
> +               x[2].len = cmd->n_dummy;
> +               x[2].tx_buf = &dummy;
> +               spi_message_add_tail(&x[2], &message);
> +       }
> +
> +       if (cmd->n_tx) {
> +               x[3].len = cmd->n_tx;
> +               x[3].tx_buf = cmd->tx_buf;
> +               spi_message_add_tail(&x[3], &message);
> +       }
> +
> +       if (cmd->n_rx) {
> +               x[3].len = cmd->n_rx;
> +               x[3].rx_buf = cmd->rx_buf;
> +               spi_message_add_tail(&x[3], &message);
> +       }
> +
> +       ret = spi_sync(spi, &message);

If any kind of locking is implicitely done by the SPI layer, you might
want to add a comment to specify it.

[snip]

> +       retval = spinand_cmd(spi_nand, &cmd);
> +
> +       if (retval != 0) {
> +               dev_err(&spi_nand->dev, "error %d reading id\n",
> +                               (int) retval);
> +               return retval;
> +       }

Just:

if (retval)
          dev_err(&spi_nand->dev, "...

return retval

[snip]

> +       retval = spinand_cmd(spi_nand, &cmd);
> +
> +       if (retval != 0) {
> +               dev_err(&spi_nand->dev, "error %d lock block\n",
> +                               (int) retval);
> +               return retval;
> +       }

Same here

[snip]

> +       if (retval != 0) {
> +               dev_err(&spi_nand->dev, "error %d reading status register\n",
> +                               (int) retval);
> +               return retval;
> +       }

And here

[snip]

> +       if (retval != 0) {
> +               dev_err(&spi_nand->dev, "error %d get otp\n",
> +                               (int) retval);
> +               return retval;
> +       }

And here

[snip]

> +       if (retval != 0) {
> +               dev_err(&spi_nand->dev, "error %d set otp\n",
> +                       (int) retval);
> +               return retval;

And here

[snip]

> +*/
> +#ifdef CONFIG_MTD_SPINAND_ONDIEECC

Same comment as above, you could probably do not make this enclosed
within an ifdef, but always compile it and test for a device flag for
instance.

> +static int spinand_enable_ecc(struct spi_device *spi_nand,
> +                       struct spinand_info *info)
> +{
> +       ssize_t retval;
> +       u8 otp = 0;
> +
> +       retval = spinand_get_otp(spi_nand, info, &otp);
> +
> +       if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
> +               return 0;
> +       } else {
> +               otp |= OTP_ECC_MASK;
> +               retval = spinand_set_otp(spi_nand, info, &otp);
> +               retval = spinand_get_otp(spi_nand, info, &otp);
> +               return retval;
> +       }

You probably do not need the if() else() because the if branch returns
immediately.

[snip]

> +       if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
> +               otp &= ~OTP_ECC_MASK;
> +               retval = spinand_set_otp(spi_nand, info, &otp);
> +               retval = spinand_get_otp(spi_nand, info, &otp);
> +               return retval;
> +       } else {
> +               return 0;

Same here

[snip]

> +static int spinand_read_page(struct spi_device *spi_nand,
> +               struct spinand_info *info, u16 page_id, u16 offset,
> +                       u16 len, u8 *rbuf)
> +{
> +       ssize_t retval;
> +       u8 status = 0;
> +
> +       retval = spinand_read_page_to_cache(spi_nand, info, page_id);

Either you check the value and return or you do not.

> +
> +       while (1) {
> +               retval = spinand_read_status(spi_nand, info, &status);
> +               if (retval < 0) {
> +                       dev_err(&spi_nand->dev, "error %d reading status register\n",
> +                                       (int) retval);
> +                       return retval;
> +               }
> +
> +               if ((status & STATUS_OIP_MASK) == STATUS_READY) {
> +                       if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
> +                               dev_err(&spi_nand->dev,
> +                                       "ecc error, page=%d\n", page_id);
> +                       }
> +                       break;
> +               }

Should not we somehow call cpu_relax() or wait for some delay here
before issuing multiple READ_STATUS commands?

[snip]

> +       retval = spinand_write_enable(spi_nand, info);
> +
> +       retval = spinand_program_data_to_cache(spi_nand, info, offset,
> +                       len, wbuf);
> +
> +       retval = spinand_program_execute(spi_nand, info, page_id);

Same here either check return value and return or do not check the
return value at all.

[snip]

> +static int spinand_get_info(struct spi_device *spi_nand,
> +               struct spinand_info *info, u8 *id)
> +{
> +       if (id[0] == 0x2C && (id[1] == 0x11 ||
> +               id[1] == 0x12 || id[1] == 0x13)) {
> +               info->mid = id[0];
> +               info->did = id[1];
> +               info->name = "MT29F1G01ZAC";
> +               info->nand_size = (1024 * 64 * 2112);
> +               info->usable_size = (1024 * 64 * 2048);
> +               info->block_size = (2112*64);
> +               info->block_main_size = (2048*64);
> +               info->block_num_per_chip = 1024;
> +               info->page_size = 2112;
> +               info->page_main_size = 2048;
> +               info->page_spare_size = 64;
> +               info->page_num_per_block = 64;
> +
> +               info->block_shift = 17;
> +               info->block_mask = 0x1ffff;
> +
> +               info->page_shift = 11;
> +               info->page_mask = 0x7ff;
> +
> +               info->ecclayout = &spinand_oob_64;
> +       }

Even if there is just one device supported by this driver, you
definitively want to use an identification table so that people can
easily add new chips without much pain.

> +       return 0;
> +}
> +
> +/**
> + * spinand_probe - [spinand Interface]
> + * @spi_nand: registered device driver.
> + *
> + * Description:
> + *   To set up the device driver parameters to make the device available.
> +*/
> +static int spinand_probe(struct spi_device *spi_nand)
> +{
> +       ssize_t retval;
> +       struct mtd_info *mtd;
> +       struct spinand_chip *chip;
> +       struct spinand_info *info;
> +       struct flash_platform_data      *data;
> +       struct mtd_part_parser_data     ppdata;
> +       u8 id[2] = {0};
> +
> +       retval = spinand_reset(spi_nand);
> +       retval = spinand_reset(spi_nand);
> +       retval = spinand_read_id(spi_nand, (u8 *)&id);
> +       if (id[0] == 0 && id[1] == 0) {
> +               pr_info(KERN_INFO "SPINAND: read id error! 0x%02x, 0x%02x!\n",
> +                       id[0], id[1]);
> +               return 0;
> +       }
> +
> +       data = spi_nand->dev.platform_data;
> +       info  = kzalloc(sizeof(struct spinand_info), GFP_KERNEL);
> +       if (!info)
> +               return -ENOMEM;

You can use devm_kzalloc() to get your chunks of memory freed upon
driver removal.

> +
> +       retval = spinand_get_info(spi_nand, info, (u8 *)&id);
> +       pr_info(KERN_INFO "SPINAND: 0x%02x, 0x%02x, %s\n",
> +               id[0], id[1], info->name);
> +       pr_info(KERN_INFO "%s\n", mu_spi_nand_driver_version);
> +       retval = spinand_lock_block(spi_nand, info, BL_ALL_UNLOCKED);
> +
> +#ifdef CONFIG_MTD_SPINAND_ONDIEECC
> +       retval = spinand_enable_ecc(spi_nand, info);
> +#else
> +       retval = spinand_disable_ecc(spi_nand, info);
> +#endif
> +
> +       ppdata.of_node = spi_nand->dev.of_node;

You could probably go along and define Device Tree bindings for this
driver at the same time, such that they are directly usable once the
driver is merged.

> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> new file mode 100644
> index 0000000..3b8802a
> --- /dev/null
> +++ b/include/linux/mtd/spinand.h
> @@ -0,0 +1,155 @@
> +/*
> + *  linux/include/linux/mtd/spinand.h
> + *  Copyright (c) 2009-2010 Micron Technology, Inc.
> + *  This software is licensed under the terms of the GNU General Public
> + *  License version 2, as published by the Free Software Foundation, and
> + *  may be copied, distributed, and modified under those terms.
> +
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> +/bin/bash: 4: command not found

?

> + *
> + *  based on nand.h
> + */
> +#ifndef __LINUX_MTD_SPI_NAND_H
> +#define __LINUX_MTD_SPI_NAND_H
> +
> +#include <linux/wait.h>
> +#include <linux/spinlock.h>
> +#include <linux/mtd/mtd.h>
> +
> +/* cmd */
> +#define CMD_READ                               0x13
> +#define CMD_READ_RDM                   0x03
> +#define CMD_PROG_PAGE_CLRCACHE 0x02
> +#define CMD_PROG_PAGE                  0x84
> +#define CMD_PROG_PAGE_EXC              0x10
> +#define CMD_ERASE_BLK                  0xd8
> +#define CMD_WR_ENABLE                  0x06
> +#define CMD_WR_DISABLE                 0x04
> +#define CMD_READ_ID                    0x9f
> +#define CMD_RESET                              0xff
> +#define CMD_READ_REG                   0x0f
> +#define CMD_WRITE_REG                  0x1f

Please prefix all of them with SPI_NAND_CMD just to be consistent with
what is defined in include/linux/mtd/nand.h?

> +
> +/* feature/ status reg */
> +#define REG_BLOCK_LOCK         0xa0
> +#define REG_OTP                                0xb0
> +#define REG_STATUS                     0xc0/* timing */
> +
> +/* status */
> +#define STATUS_OIP_MASK                0x01
> +#define STATUS_READY           (0 << 0)
> +#define STATUS_BUSY                    (1 << 0)
> +
> +#define STATUS_E_FAIL_MASK     0x04
> +#define STATUS_E_FAIL          (1 << 2)
> +
> +#define STATUS_P_FAIL_MASK     0x08
> +#define STATUS_P_FAIL          (1 << 3)
> +
> +#define STATUS_ECC_MASK                0x30
> +#define STATUS_ECC_1BIT_CORRECTED      (1 << 4)
> +#define STATUS_ECC_ERROR                       (2 << 4)
> +#define STATUS_ECC_RESERVED                    (3 << 4)
> +
> +
> +/*ECC enable defines*/
> +#define OTP_ECC_MASK           0x10
> +#define OTP_ECC_OFF                    0
> +#define OTP_ECC_ON                     1
> +
> +#define ECC_DISABLED
> +#define ECC_IN_NAND
> +#define ECC_SOFT
> +
> +/* block lock */
> +#define BL_ALL_LOCKED      0x38
> +#define BL_1_2_LOCKED      0x30
> +#define BL_1_4_LOCKED      0x28
> +#define BL_1_8_LOCKED      0x20
> +#define BL_1_16_LOCKED     0x18
> +#define BL_1_32_LOCKED     0x10
> +#define BL_1_64_LOCKED     0x08
> +#define BL_ALL_UNLOCKED    0
> +
> +struct spinand_info {
> +       u8              mid;
> +       u8              did;
> +       char            *name;
> +       u64             nand_size;
> +       u64             usable_size;
> +
> +       u32             block_size;
> +       u32             block_main_size;
> +       /*u32           block_spare_size; */
> +       u16             block_num_per_chip;
> +       u16             page_size;
> +       u16             page_main_size;
> +       u16             page_spare_size;
> +       u16             page_num_per_block;
> +       u8              block_shift;
> +       u32             block_mask;
> +       u8              page_shift;
> +       u16             page_mask;
> +
> +       struct nand_ecclayout *ecclayout;
> +};
> +
> +typedef enum {
> +       FL_READY,
> +       FL_READING,
> +       FL_WRITING,
> +       FL_ERASING,
> +       FL_SYNCING,
> +       FL_LOCKING,
> +       FL_RESETING,
> +       FL_OTPING,
> +       FL_PM_SUSPENDED,
> +} spinand_state_t;

Maybe flstate_t from include/linux/mtd/flashchip.h should be made
move/made nore generic such that you can use these defines too?
--
Florian


From helmut.raiger at hale.at  Wed Jun 26 04:03:08 2013
From: helmut.raiger at hale.at (Helmut Raiger)
Date: Wed, 26 Jun 2013 10:03:08 +0200
Subject: UBIFS: How to reserve space to be used right before power cut
In-Reply-To: <51BED0BE.2090701@hale.at>
References: <20130613135031.59037201@parrot.com>
 <1142745477.330790.1371130164128.JavaMail.root@mail.hale>
 <20130613162028.3d17bac2@parrot.com> <51BED0BE.2090701@hale.at>
Message-ID: <51CAA03C.4050000@hale.at>

On 06/17/2013 11:02 AM, Helmut Raiger wrote:
> I digged the UBI sources and still have the feeling this won't work:
>
> 1) There seems to be no way to (long term) protect a PEB from being
> moved by the wear leveling sub-system (even scrubbing on bit-flips,
> which may be induced by read-disturbances (reads on nearby pages)).
>
> 2) Temporary protection of a PEB is not really time specific, but depends
> on global PEB erase action (i.e. anything UBIFS does on the same device),
> which is something I can't control.
>
> My impression is, that UBI simply does not support this sort of
> application well. Unmoveable blocks will have a low erase count
> (below average), which is exactly what the WL should avoid.
>
> However I've never timed such a move operation:
> a) move content to a new unused PEB
> b) schedule original PEB for erasure
> It might fit into my timing requirements, but will probably be heavily
> influenced by system load and priorities.
>
> Helmut

Just an update to 'enlight the world'. We are moving to YAFFS2, it has a
deterministic garbage collector which makes it a lot easier to implement
the requested behaviour.
It seems we can even take it off the shelf, currently we are perfomance
testing the write timing.

Helmut


--
Scanned by MailScanner.



From sourav.poddar at ti.com  Thu Jun 27 00:51:21 2013
From: sourav.poddar at ti.com (Sourav Poddar)
Date: Thu, 27 Jun 2013 10:21:21 +0530
Subject: [PATCH 1/3] drivers: mtd: spinand: Add generic spinand frameowrk
 and micron driver.
In-Reply-To: <20130626152243.GA9414@kpatel.netlogicmircro.com>
References: <1372232472-2641-1-git-send-email-sourav.poddar@ti.com>
 <1372232472-2641-2-git-send-email-sourav.poddar@ti.com>
 <20130626152243.GA9414@kpatel.netlogicmircro.com>
Message-ID: <51CBC4C9.7080809@ti.com>

Hi Kamlakant,
On Wednesday 26 June 2013 08:52 PM, Kamlakant Patel wrote:
> On Wed, Jun 26, 2013 at 01:11:10PM +0530, Sourav Poddar wrote:
>> From: Mona Anonuevo<manonuevo at micron.com>
>>
>> This patch adds support for a generic spinand framework(spinand_mtd.c).
>> This frameowrk can be used for other spi based flash devices also. The idea
>> is to have a common model under drivers/mtd, as also present for other no spi
>> devices(there is a generic framework and device part simply attaches itself to it.)
>>
>> The generic frework will be used later by me for a SPI based spansion S25FL256 device.
>> The patch also contains a micron driver attaching itself to generic framework.
>>
>> Signed-off-by: Mona Anonuevo<manonuevo at micron.com>
>> Signed-off-by: Tuan Nguyen<tqnguyen at micron.com>
>> Signed-off-by: Sourav Poddar<sourav.poddar at ti.com>
>> ----
>> [I picked this as a standalone patch, can split it into generic and device part
>> based on community feedback.]
>>
>>   drivers/mtd/Kconfig               |    2 +
>>   drivers/mtd/Makefile              |    2 +
>>   drivers/mtd/spinand/Kconfig       |   24 ++
>>   drivers/mtd/spinand/Makefile      |   10 +
>>   drivers/mtd/spinand/spinand_lld.c |  776 +++++++++++++++++++++++++++++++++++++
>>   drivers/mtd/spinand/spinand_mtd.c |  690 +++++++++++++++++++++++++++++++++
>>   include/linux/mtd/spinand.h       |  155 ++++++++
>>   7 files changed, 1659 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/mtd/spinand/Kconfig
>>   create mode 100644 drivers/mtd/spinand/Makefile
>>   create mode 100644 drivers/mtd/spinand/spinand_lld.c
>>   create mode 100644 drivers/mtd/spinand/spinand_mtd.c
>>   create mode 100644 include/linux/mtd/spinand.h
>>
> I am working on Micron SPINAND(Micron MT29F1G01ZACH). I tried this patch, but it's not working.
> It is throwing following error message while mounting:
> [  260.232000] jffs2: cannot read OOB for EB at 00000000, requested 8 bytes, read 0 bytes, error -22
> mount: mounting /dev/mtdblock5 on /mnt/ failed: Input/output error
>
> I am working on it to fix into the driver, will send an updated patch with the fix.
>
Thanks for replying on this.
Since, this patch is already posted, I think it will be better if you post
the delta fix on top of this patch.
> Thanks,
> Kamlakant Patel
>



From enrico.benetti at bluewind.it  Thu Jun 27 02:44:23 2013
From: enrico.benetti at bluewind.it (enrico benetti)
Date: Thu, 27 Jun 2013 08:44:23 +0200
Subject: UBIFS: power cut test on 2.6.35 + NOR
Message-ID: <51CBDF47.709@bluewind.it>

Hi All,
I'd need a hint on the best way to go on with my development.

I'm working on a custom target based on 2.6.35.3 kernel with NOR device.

UBIFS R/W partitions seem not robust against power cut tests: I'm using
integck 1.4.9 and I can have unrecoverable errors on tested volume when
performing real power cuts.

First of all, I've done several MTD stress tests to validate the low
level driver.
I've checked git repos, and
http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/  
<http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/shortlog>
is updated to 08/2012 (that is approx 3.7.1 kernel revision) and no more
supported.

  From several discussions on the list I think the best way to solve (or
at least to have a better behaviour with ubi/ubifs) could be to get the
patches from this repo and merge them with my sources.

Do you agree or is it better to do more investigation on current issues?

Thanks in advance for your support,
Enrico



From nvbolhuis at aimvalley.nl  Thu Jun 27 05:32:02 2013
From: nvbolhuis at aimvalley.nl (Norbert van Bolhuis)
Date: Thu, 27 Jun 2013 11:32:02 +0200
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <51CBDF47.709@bluewind.it>
References: <51CBDF47.709@bluewind.it>
Message-ID: <51CC0692.6010507@aimvalley.nl>

On 06/27/13 08:44, enrico benetti wrote:
> Hi All,
> I'd need a hint on the best way to go on with my development.
>
> I'm working on a custom target based on 2.6.35.3 kernel with NOR device.
>
> UBIFS R/W partitions seem not robust against power cut tests: I'm using
> integck 1.4.9 and I can have unrecoverable errors on tested volume when
> performing real power cuts.
>
> First of all, I've done several MTD stress tests to validate the low
> level driver.
> I've checked git repos, and
> http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/ <http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/shortlog>
> is updated to 08/2012 (that is approx 3.7.1 kernel revision) and no more
> supported.
>
>  From several discussions on the list I think the best way to solve (or
> at least to have a better behaviour with ubi/ubifs) could be to get the
> patches from this repo and merge them with my sources.
>
> Do you agree or is it better to do more investigation on current issues?
>
> Thanks in advance for your support,
> Enrico
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
>

yes, use http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git to update.

it has several "NOR power cut" fixes, for example:

http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/commit/152780c61d65b0cc5cd5cc974e926a9c47534d5e
http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/commit/9258edaca1d7b36abd0e23661579c35fe9c4f00f
http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/commit/e5d7669e2fa0797c0c110fa9bf3e51b013ba399b

which I doubt are in 2.6.35.3

Btw. we used the (no longer available) http://git.infradead.org/users/dedekind/ubifs-v2.6.29.git
(that has been kept up-to-date with mainline till June 2011) to update our sources, and we see
no NOR power cut issues.

---
N. van Bolhuis.


From Mats.Karrman at tritech.se  Thu Jun 27 05:37:18 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 27 Jun 2013 09:37:18 +0000
Subject: xattr patches from feb?
In-Reply-To: <51C837D9.5060007@pengutronix.de>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FCA20D3@post.tritech.se>,
 <51C837D9.5060007@pengutronix.de>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8176@post.tritech.se>

Hi Marc,

Thanks for your response! it was held captive by the spam filter for a while (my fault) so I didn't notice it.
I know about customers and changing priorities ;)

I havn't received any patches from you yet (also a mail program issue?).
I have only adopted 1/5 "xattr: protect ui_size and data_len by ui_mutex" and 2/5 "fix couple bugs in
UBIFS extended attribute len" (appended below).
Those two seem to work well (testing still in progress) and should not be affected by the locking issue?

BR // Mats

---------------------------
diff -pruN a/fs/ubifs/journal.c b/fs/ubifs/journal.c
--- a/fs/ubifs/journal.c	2013-06-24 15:06:39.213689332 +0200
+++ b/fs/ubifs/journal.c	2013-06-24 15:26:36.842825120 +0200
@@ -553,7 +553,8 @@ int ubifs_jnl_update(struct ubifs_info *
 
 	dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
 		inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
-	ubifs_assert(dir_ui->data_len == 0);
+	if (!xent)
+		ubifs_assert(dir_ui->data_len == 0);
 	ubifs_assert(mutex_is_locked(&dir_ui->ui_mutex));
 
 	dlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
@@ -573,6 +574,8 @@ int ubifs_jnl_update(struct ubifs_info *
 	aligned_dlen = ALIGN(dlen, 8);
 	aligned_ilen = ALIGN(ilen, 8);
 	len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
+	len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ +
+	      dir_ui->data_len;
 	dent = kmalloc(len, GFP_NOFS);
 	if (!dent)
 		return -ENOMEM;
@@ -649,7 +652,8 @@ int ubifs_jnl_update(struct ubifs_info *
 
 	ino_key_init(c, &ino_key, dir->i_ino);
 	ino_offs += aligned_ilen;
-	err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ);
+	err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs,
+			    UBIFS_INO_NODE_SZ + dir_ui->data_len);
 	if (err)
 		goto out_ro;
 
diff -pruN a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
--- a/fs/ubifs/xattr.c	2013-06-24 15:06:39.233689282 +0200
+++ b/fs/ubifs/xattr.c	2013-06-24 15:12:12.196863493 +0200
@@ -143,10 +143,10 @@ static int create_xattr(struct ubifs_inf
 		err = -ENOMEM;
 		goto out_free;
 	}
-	inode->i_size = ui->ui_size = size;
-	ui->data_len = size;
 
 	mutex_lock(&host_ui->ui_mutex);
+	inode->i_size = ui->ui_size = size;
+	ui->data_len = size;
 	host->i_ctime = ubifs_current_time(host);
 	host_ui->xattr_cnt += 1;
 	host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
@@ -208,10 +208,10 @@ static int change_xattr(struct ubifs_inf
 		err = -ENOMEM;
 		goto out_free;
 	}
-	inode->i_size = ui->ui_size = size;
-	ui->data_len = size;
 
 	mutex_lock(&host_ui->ui_mutex);
+	inode->i_size = ui->ui_size = size;
+	ui->data_len = size;
 	host->i_ctime = ubifs_current_time(host);
 	host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
 	host_ui->xattr_size += CALC_XATTR_BYTES(size);
---------------------------


From mkl at pengutronix.de  Thu Jun 27 05:51:17 2013
From: mkl at pengutronix.de (Marc Kleine-Budde)
Date: Thu, 27 Jun 2013 11:51:17 +0200
Subject: xattr patches from feb?
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8176@post.tritech.se>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FCA20D3@post.tritech.se>,
 <51C837D9.5060007@pengutronix.de>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8176@post.tritech.se>
Message-ID: <51CC0B15.8080804@pengutronix.de>

On 06/27/2013 11:37 AM, Mats K?rrman wrote:
> Thanks for your response! it was held captive by the spam filter for
> a while (my fault) so I didn't notice it. I know about customers and
> changing priorities ;)
> 
> I havn't received any patches from you yet (also a mail program
> issue?).

Maybe, I'll push the patches to our git server:

http://git.pengutronix.de/?p=mkl/linux.git;a=shortlog;h=refs/heads/v3.10/topic/ubifs-xattr

> I have only adopted 1/5 "xattr: protect ui_size and data_len by ui_mutex" and 2/5 "fix couple bugs in
> UBIFS extended attribute len" (appended below).
> Those two seem to work well (testing still in progress) and should not be affected by the locking issue?

Can you please (re)check if these patches are still the ones on my
server? Can I have your Tested-by? Do they fix your problems? If so, we
should try to get them mainline.

And yes, the first two patches are unrelated to locking problem. The
locking problems are "introduced" by "UBIFS: Add security.* XATTR
support for the UBIFS" I think.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20130627/1e6b344d/attachment.sig>

From Mats.Karrman at tritech.se  Thu Jun 27 06:47:00 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 27 Jun 2013 10:47:00 +0000
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <51CBDF47.709@bluewind.it>
References: <51CBDF47.709@bluewind.it>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>

Hi Enrico,

> From: linux-mtd [linux-mtd-bounces at lists.infradead.org] on behalf of enrico benetti [enrico.benetti at bluewind.it]
> Sent: Thursday, June 27, 2013 8:44 AM
> To: linux-mtd at lists.infradead.org
> Subject: UBIFS: power cut test on 2.6.35 + NOR

> I've checked git repos, and
> http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/
> <http://git.infradead.org/users/dedekind/ubifs-v2.6.35.git/shortlog>
> is updated to 08/2012 (that is approx 3.7.1 kernel revision) and no more
> supported.

I'm using 2.6.35.14 (last 2.6.35) with all UBIFS patches from the
repo you mentioned above. I have also added/ported all patches from
mainline 3.9 stable (excluding those only dealing with debug prints etc).

Still I have some minor (I hope) issues after running integck power-cut
tests for several days. They manifest in errors on xattr nodes.
There are some related patches in discussion, see:
http://thread.gmane.org/gmane.linux.kernel.lsm/18746
http://thread.gmane.org/gmane.linux.drivers.mtd/47021

BR // Mats

From Mats.Karrman at tritech.se  Thu Jun 27 06:59:40 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 27 Jun 2013 10:59:40 +0000
Subject: xattr patches from feb?
In-Reply-To: <51CC0B15.8080804@pengutronix.de>
References: <ED3E0BCACD909541BA94A34C4A164D4C4FCA20D3@post.tritech.se>,
 <51C837D9.5060007@pengutronix.de>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8176@post.tritech.se>,
 <51CC0B15.8080804@pengutronix.de>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FCA820E@post.tritech.se>

On Thu, June 27, 2013 11:51 AM, Marc Kleine-Budde [mkl at pengutronix.de] wrote:
> Can you please (re)check if these patches are still the ones on my
> server?

Yes, my patch is equivalent to your committs
1a5ef9e82c7c76a90de94190df6d0ad9cfad2452
and
88dfd5c021b6a628a3b51e8f9f34e4d26a01f4f4

> Can I have your Tested-by? Do they fix your problems?

I'm still testing but so far it looks promising.

> If so, we should try to get them mainline.

Sounds like a great idea!

// Mats

From enrico.benetti at bluewind.it  Thu Jun 27 08:56:09 2013
From: enrico.benetti at bluewind.it (enrico benetti)
Date: Thu, 27 Jun 2013 14:56:09 +0200
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>
References: <51CBDF47.709@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>
Message-ID: <51CC3669.103@bluewind.it>


> I'm using 2.6.35.14 (last 2.6.35) with all UBIFS patches from the
> repo you mentioned above. I have also added/ported all patches from
> mainline 3.9 stable (excluding those only dealing with debug prints etc).
>
> Still I have some minor (I hope) issues after running integck power-cut
> tests for several days. They manifest in errors on xattr nodes.
> There are some related patches in discussion, see:
> http://thread.gmane.org/gmane.linux.kernel.lsm/18746
> http://thread.gmane.org/gmane.linux.drivers.mtd/47021
>
>
Hi Mats, Norbert,
thanks for your kind feedbacks.

Mats, are you working on a NOR-based system or are you referring to NAND?

I'm going to merge from 2.6.35 back-port repo and I'll let you know.

Regards,
E




From Mats.Karrman at tritech.se  Thu Jun 27 09:01:40 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Thu, 27 Jun 2013 13:01:40 +0000
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <51CC3669.103@bluewind.it>
References: <51CBDF47.709@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>,
 <51CC3669.103@bluewind.it>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>

>From: linux-mtd [linux-mtd-bounces at lists.infradead.org] on behalf of enrico benetti [enrico.benetti at bluewind.it]
>Sent: Thursday, June 27, 2013 2:56 PM
>To: linux-mtd at lists.infradead.org
>Subject: Re: UBIFS: power cut test on 2.6.35 + NOR
>
>> I'm using 2.6.35.14 (last 2.6.35) with all UBIFS patches from the
>> repo you mentioned above. I have also added/ported all patches from
>> mainline 3.9 stable (excluding those only dealing with debug prints etc).
>>
>> Still I have some minor (I hope) issues after running integck power-cut
>> tests for several days. They manifest in errors on xattr nodes.
>> There are some related patches in discussion, see:
>> http://thread.gmane.org/gmane.linux.kernel.lsm/18746
>> http://thread.gmane.org/gmane.linux.drivers.mtd/47021
>>
>>
>Hi Mats, Norbert,
>thanks for your kind feedbacks.
>
>Mats, are you working on a NOR-based system or are you referring to NAND?

NOR

>
>I'm going to merge from 2.6.35 back-port repo and I'll let you know.
>
>Regards,
>E


From pekon at ti.com  Thu Jun 27 13:50:33 2013
From: pekon at ti.com (Gupta, Pekon)
Date: Thu, 27 Jun 2013 17:50:33 +0000
Subject: [PATCH v3 0/4] mtd:nand:omap2: clean-up of supported ECC schemes
In-Reply-To: <1372010299-30141-1-git-send-email-pekon@ti.com>
References: <1372010299-30141-1-git-send-email-pekon@ti.com>
Message-ID: <20980858CB6D3A4BAE95CA194937D5E73E9E0763@DBDE04.ent.ti.com>

To OMAP3/4/5 and AM335x users,

Though I have tested the following series on AM335x-EVM, 
but it would be good if it can also be tested on other platforms like
OMAP3/4/5 custom boards which use NAND.

This would be helpful, as this patch series provides base for further 
enhancement and cleanup of omap2-nand driver.


with regards, pekon


> -----Original Message-----
> From: Gupta, Pekon
> Sent: Sunday, June 23, 2013 11:28 PM
> To: tony at atomide.com; artem.bityutskiy at linux.intel.com; Cousson, Benoit
> Cc: arnd at arndb.de; Philip, Avinash; Balbi, Felipe; linux-
> mtd at lists.infradead.org; linux-omap at vger.kernel.org;
> jp.francois at cynove.com; Gupta, Pekon
> Subject: [PATCH v3 0/4] mtd:nand:omap2: clean-up of supported ECC
> schemes
> 
> (with Author Name fixed)
> Changes v2 -> v3
> - PATCH-1: re-arranged code to remove redundancy, added
> NAND_BUSWIDTH_AUTO
> - PATCH-2: updated nand-ecc-opt DT mapping and Documentation
> - PATCH-3: code-cleaning + changes to match PATCH-1
> - PATCH-4 <DROPPED> update DT attribute for ti,nand-ecc-opt
> 	- received feedback to keep DT mapping independent of linuxism
> - PATCH-4:<NEW> : ARM: dts: AM33xx: updated default ECC scheme in nand-
> ecc-opt
> 	- independent patch for AM335x-evm.dts update based on PATCH-2
> 
> Changes v1 -> v2
> 	added 	[PATCH 3/4] and [PATCH 4/4]
> 
> Patches in this series:
> [PATCH 1/4]: clean-up and optimization for supported ECC schemes.
> [PATCH 2/4]: add separate DT options each supported ECC scheme.
> [PATCH 3/4]: update BCH4 ECC implementation (using ELM or using lib/bch.h)
> [PATCH 4/4]: ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-
> opt
> 
> After this patch series, omap2-nand driver will supports following ECC
> schemes:
> +---------------------------------------+---------------+---------------+
> | ECC scheme				|ECC calculation|Error detection|
> +---------------------------------------+---------------+---------------+
> |OMAP_ECC_HAMMING_CODE_DEFAULT		|S/W		|S/W
> 		|
> |OMAP_ECC_HAMMING_CODE_HW		|H/W (GPMC)	|S/W
> 	|
> |OMAP_ECC_HAMMING_CODE_HW_ROMCODE	|H/W (GPMC)	|S/W
> 		|
> +---------------------------------------+---------------+---------------+
> |OMAP_ECC_BCH4_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W
> (lib/bch.h)|
> |OMAP_ECC_BCH4_CODE_HW			|H/W (GPMC)	|H/W (ELM)
> 	|
> +---------------------------------------+---------------+---------------+
> |OMAP_ECC_BCH8_CODE_HW_DETECTION_SW	|H/W (GPMC)	|S/W
> (lib/bch.h)|
> |OMAP_ECC_BCH8_CODE_HW			|H/W (GPMC)	|H/W (ELM)
> 	|
> +---------------------------------------+---------------+---------------+
> - Selection of OMAP_ECC_BCHx_CODE_HW_DETECTION_SW requires,
> 	Kconfig: CONFIG_MTD_NAND_ECC_BCH: enables S/W based BCH
> ECC algorithm.
> 
> - Selection of OMAP_ECC_BCHx_CODE_HW requires,
> 	Kconfig: CONFIG_MTD_NAND_OMAP_BCH: enables ELM H/W
> module.
> 
> 
> Pekon Gupta (4):
>   mtd:nand:omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in
>     device_probe
>   ARM: OMAP2+: cleaned-up DT support of various ECC schemes
>   mtd:nand:omap2: updated support for BCH4 ECC scheme
>   ARM: dts: AM33xx: updated default ECC scheme in nand-ecc-opt
> 
>  .../devicetree/bindings/mtd/gpmc-nand.txt          |  65 ++-
>  arch/arm/boot/dts/am335x-evm.dts                   |   2 +-
>  arch/arm/mach-omap2/gpmc.c                         |  14 +-
>  drivers/mtd/nand/Kconfig                           |   7 +-
>  drivers/mtd/nand/omap2.c                           | 482 ++++++++++-----------
>  include/linux/platform_data/elm.h                  |   4 +
>  include/linux/platform_data/mtd-nand-omap2.h       |  22 +-
>  7 files changed, 307 insertions(+), 289 deletions(-)
> 
> --
> 1.8.1



From Mats.Karrman at tritech.se  Fri Jun 28 05:05:12 2013
From: Mats.Karrman at tritech.se (=?iso-8859-1?Q?Mats_K=E4rrman?=)
Date: Fri, 28 Jun 2013 09:05:12 +0000
Subject: UBIFS failure & stable page writes
In-Reply-To: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F546220@SI-MBX14.de.bosch.com>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
 <51C005B8.3000709@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F546220@SI-MBX14.de.bosch.com>
Message-ID: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8761@post.tritech.se>

Hi Anton,

Thanks for your efforts!
The tests I have run has shown no regressions, but some stability improvements in the integck test.
(I still have not been able to reproduce the orphan node 1 problem myself though.)

A question; do you use file extended attributes? I have seen problems in this area while running
integck and also tested patches that seem to help.
ref: http://thread.gmane.org/gmane.linux.drivers.mtd/47021

BR // Mats

> From: Prins Anton (ST-CO/ENG1.1) [Anton.Prins at nl.bosch.com]
> Sent: Tuesday, June 25, 2013 10:21 AM
> To: Adrian Hunter
> Cc: Mats K?rrman; linux-mtd at lists.infradead.org; dedekind1 at gmail.com
> Subject: RE: UBIFS failure & stable page writes
> 
> Another weekend of tests, including the patches showed no more logging of writing orphan node 0.
> Also the 0xdead4ead did not appear; so the patches certainly do their job!
> 
> We do not have hard evidence the missing root node is caused by this 'writing of free-ed memory'.
> But at least it seems a good suspect! Because the occurrence is very low we will continue testing...
> (And go back mounting synchronous to get some higher occurrence...)
> 
> I'll keep you up-to-date.
> 
> Anton


From naveen.mamindlapalli at gmail.com  Fri Jun 28 05:11:04 2013
From: naveen.mamindlapalli at gmail.com (Naveen Mamindlapalli)
Date: Fri, 28 Jun 2013 14:41:04 +0530
Subject: ONFI commands support in MTD
Message-ID: <CAOcd1mqKRzASwUUuk5_TyceN4cEppgDYw4UQHA5yTzMpmLmhiw@mail.gmail.com>

Hi,

Does the Linux MTD layer supports ONFI commands like multi-plane
commands, page cache commands?

Thanks and Regards,
Naveen


From Anton.Prins at nl.bosch.com  Fri Jun 28 05:27:42 2013
From: Anton.Prins at nl.bosch.com (Prins Anton (ST-CO/ENG1.1))
Date: Fri, 28 Jun 2013 11:27:42 +0200
Subject: UBIFS failure & stable page writes
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8761@post.tritech.se>
References: <85D877DD6EE67B4A9FCA9B9C3A4865670C3E8CB9B7@SI-MBX14.de.bosch.com>
 <1369732266.5446.117.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91DC9C@SI-MBX14.de.bosch.com>
 <1369810158.5446.208.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3E91E697@SI-MBX14.de.bosch.com>
 <1370239282.21714.21.camel@sauron.fi.intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3EA0F38E@SI-MBX14.de.bosch.com>
 <51B82A1D.30009@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3508@SI-MBX14.de.bosch.com>
 <51B862D6.2080807@intel.com>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3590@SI-MBX14.de.bosch.com>
 <51B87315.7090808@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A36BC@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8F091@post.tritech.se>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F1A3D7F@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FC8FD66@post.tritech.se>
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F4167DD@SI-MBX14.de.bosch.com>
 <51C005B8.3000709@intel.com>,
 <85D877DD6EE67B4A9FCA9B9C3A4865670C3F546220@SI-MBX14.de.bosch.com>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8761@post.tritech.se>
Message-ID: <85D877DD6EE67B4A9FCA9B9C3A4865670C3F5B77AD@SI-MBX14.de.bosch.com>

Hi Mats,

We are not using extended attributes, so I expect no relation with our findings.

Thanks,

Anton

-----Original Message-----
From: Mats K?rrman [mailto:Mats.Karrman at tritech.se] 
Sent: vrijdag 28 juni 2013 11:05
To: Prins Anton (ST-CO/ENG1.1); Adrian Hunter
Cc: linux-mtd at lists.infradead.org; dedekind1 at gmail.com
Subject: RE: UBIFS failure & stable page writes

Hi Anton,

Thanks for your efforts!
The tests I have run has shown no regressions, but some stability improvements in the integck test.
(I still have not been able to reproduce the orphan node 1 problem myself though.)

A question; do you use file extended attributes? I have seen problems in this area while running
integck and also tested patches that seem to help.
ref: http://thread.gmane.org/gmane.linux.drivers.mtd/47021

BR // Mats

> From: Prins Anton (ST-CO/ENG1.1) [Anton.Prins at nl.bosch.com]
> Sent: Tuesday, June 25, 2013 10:21 AM
> To: Adrian Hunter
> Cc: Mats K?rrman; linux-mtd at lists.infradead.org; dedekind1 at gmail.com
> Subject: RE: UBIFS failure & stable page writes
> 
> Another weekend of tests, including the patches showed no more logging of writing orphan node 0.
> Also the 0xdead4ead did not appear; so the patches certainly do their job!
> 
> We do not have hard evidence the missing root node is caused by this 'writing of free-ed memory'.
> But at least it seems a good suspect! Because the occurrence is very low we will continue testing...
> (And go back mounting synchronous to get some higher occurrence...)
> 
> I'll keep you up-to-date.
> 
> Anton


From dedekind1 at gmail.com  Fri Jun 28 07:15:15 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Fri, 28 Jun 2013 14:15:15 +0300
Subject: [PATCH 2/2] UBIFS: fix a horrid bug
In-Reply-To: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>
References: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>
Message-ID: <1372418115-16713-2-git-send-email-dedekind1@gmail.com>

From: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>

Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no
mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are
in the middle of 'ubifs_readdir()'.

This means that 'file->private_data' can be freed while 'ubifs_readdir()' uses
it, and this is a very bad bug: not only 'ubifs_readdir()' can return garbage,
but this may corrupt memory and lead to all kinds of problems like crashes an
security holes.

This patch fixes the problem by using the 'file->f_version' field, which
'->llseek()' always unconditionally sets to zero. We set it to 1 in
'ubifs_readdir()' and whenever we detect that it became 0, we know there was a
seek and it is time to clear the state saved in 'file->private_data'.

I tested this patch by writing a user-space program which runds readdir and
seek in parallell. I could easily crash the kernel without these patches, but
could not crash it with these patches.

Cc: stable at vger.kernel.org
Reported-by: Al Viro <viro at zeniv.linux.org.uk>
Tested-by: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
---
 fs/ubifs/dir.c |   30 +++++++++++++++++++++++++++---
 1 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 8e587af..605af51 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -365,6 +365,24 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 		 */
 		return 0;
 
+	if (file->f_version == 0) {
+		/*
+		 * The file was seek'ed, which means that @file->private_data
+		 * is now invalid. This may also be just the first
+		 * 'ubifs_readdir()' invocation, in which case
+		 * @file->private_data is NULL, and the below code is
+		 * basically a no-op.
+		 */
+		kfree(file->private_data);
+		file->private_data = NULL;
+	}
+
+	/*
+	 * 'generic_file_llseek()' unconditionally sets @file->f_version to
+	 * zero, and we use this for detecting whether the file was seek'ed.
+	 */
+	file->f_version = 1;
+
 	/* File positions 0 and 1 correspond to "." and ".." */
 	if (pos == 0) {
 		ubifs_assert(!file->private_data);
@@ -438,6 +456,14 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 		file->f_pos = pos = key_hash_flash(c, &dent->key);
 		file->private_data = dent;
 		cond_resched();
+
+		if (file->f_version == 0)
+			/*
+			 * The file was seek'ed meanwhile, lets return and start
+			 * reading direntries from the new position on the next
+			 * invocation.
+			 */
+			return 0;
 	}
 
 out:
@@ -448,15 +474,13 @@ out:
 
 	kfree(file->private_data);
 	file->private_data = NULL;
+	/* 2 is a special value indicating that there are no more direntries */
 	file->f_pos = 2;
 	return 0;
 }
 
-/* If a directory is seeked, we have to free saved readdir() state */
 static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence)
 {
-	kfree(file->private_data);
-	file->private_data = NULL;
 	return generic_file_llseek(file, offset, whence);
 }
 
-- 
1.7.7.6



From dedekind1 at gmail.com  Fri Jun 28 07:15:14 2013
From: dedekind1 at gmail.com (Artem Bityutskiy)
Date: Fri, 28 Jun 2013 14:15:14 +0300
Subject: [PATCH 1/2] UBIFS: prepare to fix a horrid bug
Message-ID: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>

From: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>

Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no
mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are
in the middle of 'ubifs_readdir()'.

First of all, this means that 'file->private_data' can be freed while
'ubifs_readdir()' uses it.  But this particular patch does not fix the problem.
This patch is only a preparation, and the fix will follow next.

In this patch we make 'ubifs_readdir()' stop using 'file->f_pos' directly,
because 'file->f_pos' can be changed by '->llseek()' at any point. This may
lead 'ubifs_readdir()' to returning inconsistent data: directory entry names
may correspond to incorrect file positions.

So here we introduce a local variable 'pos', read 'file->f_pose' once at very
the beginning, and then stick to 'pos'. The result of this is that when
'ubifs_dir_llseek()' changes 'file->f_pos' while we are in the middle of
'ubifs_readdir()', the latter "wins".

Cc: stable at vger.kernel.org
Reported-by: Al Viro <viro at zeniv.linux.org.uk>
Tested-by: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
---
 fs/ubifs/dir.c |   24 ++++++++++++------------
 1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index de08c92f..8e587af 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -349,15 +349,16 @@ static unsigned int vfs_dent_type(uint8_t type)
 static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
 	int err, over = 0;
+	loff_t pos = file->f_pos;
 	struct qstr nm;
 	union ubifs_key key;
 	struct ubifs_dent_node *dent;
 	struct inode *dir = file_inode(file);
 	struct ubifs_info *c = dir->i_sb->s_fs_info;
 
-	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos);
 
-	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
+	if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2)
 		/*
 		 * The directory was seek'ed to a senseless position or there
 		 * are no more entries.
@@ -365,15 +366,15 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 		return 0;
 
 	/* File positions 0 and 1 correspond to "." and ".." */
-	if (file->f_pos == 0) {
+	if (pos == 0) {
 		ubifs_assert(!file->private_data);
 		over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
 		if (over)
 			return 0;
-		file->f_pos = 1;
+		file->f_pos = pos = 1;
 	}
 
-	if (file->f_pos == 1) {
+	if (pos == 1) {
 		ubifs_assert(!file->private_data);
 		over = filldir(dirent, "..", 2, 1,
 			       parent_ino(file->f_path.dentry), DT_DIR);
@@ -389,7 +390,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 			goto out;
 		}
 
-		file->f_pos = key_hash_flash(c, &dent->key);
+		file->f_pos = pos = key_hash_flash(c, &dent->key);
 		file->private_data = dent;
 	}
 
@@ -397,17 +398,16 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 	if (!dent) {
 		/*
 		 * The directory was seek'ed to and is now readdir'ed.
-		 * Find the entry corresponding to @file->f_pos or the
-		 * closest one.
+		 * Find the entry corresponding to @pos or the closest one.
 		 */
-		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
+		dent_key_init_hash(c, &key, dir->i_ino, pos);
 		nm.name = NULL;
 		dent = ubifs_tnc_next_ent(c, &key, &nm);
 		if (IS_ERR(dent)) {
 			err = PTR_ERR(dent);
 			goto out;
 		}
-		file->f_pos = key_hash_flash(c, &dent->key);
+		file->f_pos = pos = key_hash_flash(c, &dent->key);
 		file->private_data = dent;
 	}
 
@@ -419,7 +419,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 			     ubifs_inode(dir)->creat_sqnum);
 
 		nm.len = le16_to_cpu(dent->nlen);
-		over = filldir(dirent, dent->name, nm.len, file->f_pos,
+		over = filldir(dirent, dent->name, nm.len, pos,
 			       le64_to_cpu(dent->inum),
 			       vfs_dent_type(dent->type));
 		if (over)
@@ -435,7 +435,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 		}
 
 		kfree(file->private_data);
-		file->f_pos = key_hash_flash(c, &dent->key);
+		file->f_pos = pos = key_hash_flash(c, &dent->key);
 		file->private_data = dent;
 		cond_resched();
 	}
-- 
1.7.7.6



From joakim.tjernlund at transmode.se  Fri Jun 28 08:27:58 2013
From: joakim.tjernlund at transmode.se (Joakim Tjernlund)
Date: Fri, 28 Jun 2013 14:27:58 +0200
Subject: [PATCH 1/2] UBIFS: prepare to fix a horrid bug
In-Reply-To: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>
References: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>
Message-ID: <OF2055C26B.290CB8FD-ONC1257B98.00446680-C1257B98.00447A62@transmode.se>

"linux-mtd" <linux-mtd-bounces at lists.infradead.org> wrote on 2013/06/28 
13:15:14:
> 
> From: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
> 
> Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have 
no
> mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while 
we are
> in the middle of 'ubifs_readdir()'.
> 
> First of all, this means that 'file->private_data' can be freed while
> 'ubifs_readdir()' uses it.  But this particular patch does not fix the 
problem.
> This patch is only a preparation, and the fix will follow next.
> 
> In this patch we make 'ubifs_readdir()' stop using 'file->f_pos' 
directly,
> because 'file->f_pos' can be changed by '->llseek()' at any point. This 
may
> lead 'ubifs_readdir()' to returning inconsistent data: directory entry 
names
> may correspond to incorrect file positions.
> 
> So here we introduce a local variable 'pos', read 'file->f_pose' once at 
very
> the beginning, and then stick to 'pos'. The result of this is that when
> 'ubifs_dir_llseek()' changes 'file->f_pos' while we are in the middle of
> 'ubifs_readdir()', the latter "wins".

Ouch, I hope JFFS2 doesn't have the same bug?

 Jcoe


From enrico.benetti at bluewind.it  Fri Jun 28 09:36:40 2013
From: enrico.benetti at bluewind.it (enrico benetti)
Date: Fri, 28 Jun 2013 15:36:40 +0200
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>
References: <51CBDF47.709@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>,
 <51CC3669.103@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>
Message-ID: <51CD9168.7000902@bluewind.it>


>> I'm going to merge from 2.6.35 back-port repo and I'll let you know.
>>
Hi All,
I've merged down all 2.6.35 git repo patches and started again power cut
tests with integck.

After a whirl, I had an unrecoverable error during volume mount:

[   18.060413] UBI: attaching mtd7 to ubi0
[   18.064335] UBI: physical eraseblock size:   131072 bytes (128 KiB)
[   18.070608] UBI: logical eraseblock size:    130944 bytes
[   18.076025] UBI: smallest flash I/O unit:    1
[   18.080472] UBI: VID header offset:          64 (aligned 64)
[   18.086145] UBI: data offset:                128
[   18.121404] UBI: attached mtd7 to ubi0
[   18.125167] UBI: MTD device name:            "wfs"
[   18.129962] UBI: MTD device size:            10 MiB
[   18.137534] UBI: number of good PEBs:        80
[   18.142129] UBI: number of bad PEBs:         0
[   18.146576] UBI: max. allowed volumes:       128
[   18.151196] UBI: wear-leveling threshold:    4096
[   18.155916] UBI: number of internal volumes: 1
[   18.160362] UBI: number of user volumes:     1
[   18.164818] UBI: available PEBs:             0
[   18.169264] UBI: total number of reserved PEBs: 80
[   18.174071] UBI: number of PEBs reserved for bad PEB handling: 0
[   18.180083] UBI: max/mean erase counter: 527/487
[   18.184741] UBI: image sequence number: 0
[   18.188766] UBI: background thread "ubi_bgt0d" started, PID 1219
UBI device number 0, total 80 LEBs (10475520 bytes, 10.0 MiB), available
0 LEBs (0 bytes), LEB size 130944 bytes (127.9 KiB)
[   20.391279] MTD do_write_buffer(): software timeout
[   20.452081] UBI error: nor_erase_prepare: cannot invalidate PEB 25,
write returned -5 read returned 2

Digging the web, I've found several discussions on write-timeout with
NOR devices (cfr.http://lists.infradead.org/pipermail/linux-mtd/2013-June/047177.html),
but this seems not to be the root cause.

Disabling background thread I was still not able to mount the volume,
but this patch (http://git.infradead.org/ubifs-2.6.git/commit/6fb4374f6b1b3932f3acfe9d353568d3d8599cad)
solved and at least mounting is ok.

As soon as write operations are performed on the filesystem again
there's a failure: it seems sector erasure is not properly
handled/requested.

Flash dump shows PEB 25 this way (= partially erased), so it turns out write operation can't work:

------------------------------------------------------------
00320040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
|................|
*
003201e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
|................|
*
00320220  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
|................|
*
003203e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
|................|
*
00320820  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
|................|
*
------------------------------------------------------------

Please note that I'm using a 'slow' device (M29EW), with a maximum
sector erasure time of 4 secs, and this seems to stress asynchronous
operations with ubifs and integck test.

I'll go on with commit log analysis to check if this kind of issue is
already solved/discussed.

Full partition erasure has solved mount/fs issue, as expected.

Regards,
E



From viro at ZenIV.linux.org.uk  Fri Jun 28 09:54:08 2013
From: viro at ZenIV.linux.org.uk (Al Viro)
Date: Fri, 28 Jun 2013 14:54:08 +0100
Subject: [PATCH 1/2] UBIFS: prepare to fix a horrid bug
In-Reply-To: <OF2055C26B.290CB8FD-ONC1257B98.00446680-C1257B98.00447A62@transmode.se>
References: <1372418115-16713-1-git-send-email-dedekind1@gmail.com>
 <OF2055C26B.290CB8FD-ONC1257B98.00446680-C1257B98.00447A62@transmode.se>
Message-ID: <20130628135408.GG4165@ZenIV.linux.org.uk>

On Fri, Jun 28, 2013 at 02:27:58PM +0200, Joakim Tjernlund wrote:
> > So here we introduce a local variable 'pos', read 'file->f_pose' once at 
> very
> > the beginning, and then stick to 'pos'. The result of this is that when
> > 'ubifs_dir_llseek()' changes 'file->f_pos' while we are in the middle of
> > 'ubifs_readdir()', the latter "wins".
> 
> Ouch, I hope JFFS2 doesn't have the same bug?

FWIW, this class of bugs (f_pos races, *not* kfree-under-us) is dealt with
by switch to saner API - see commits in linux-next marked [readdir] <something>



From zhengun23 at 126.com  Fri Jun 28 10:48:43 2013
From: zhengun23 at 126.com (zhengjun)
Date: Fri, 28 Jun 2013 22:48:43 +0800 (CST)
Subject: why use a very low-efficient method to check all the uncheked inode
 in garbage_collect_pass
Message-ID: <7f412749.1fc36.13f8b41f860.Coremail.zhengun23@126.com>

I encountered a problem with my linux system?uses jffs2 file system?
After scan all inode on the flash, a background thread ( garbage_collect_thread) is start? Before collecting,
it begins with checking crc of all inodes in inode_cache_list. But unluckly the checking work cost all most 3
minutes?It costs the 98% of all cpu resource.
I found that the time is wasted on finding out the valid inode_cache with specified inode id (c->checked_ino)?
checked_ino is counted from zero to c->higest_ino? 
In my system, there are 3000 files,but with higest_ino reached to 27262976?
(Because the old file is replaced by new file, by first delete then copy)?
So the most of time, jffs2_get_inode_cache can not find a valid inode with c->checked_ino?
So the useless search works wastes a lot of time.
why?
why use a increased  index to find each indoe_cache in inode_cache_list? but you never know which index is the valide ino.
The indode_cache_list is a hash table.
why not use a deep-first-search method to get each inode in hash table?
Just remember next valid ino in c->checked_ino.

Now I designed a new search method? It works much more efficiently.

Could you optimize these code for better work?  Thanks!

jffs2_garbage_collect_pass()
{
   ....
    if( c->unchecked_size )
    {
        ic = jffs2_get_inode_cache_next( c, & c->checked_ino );  // new search method

       if( !ic )
      {
         BUG();
      }
   }
....
}

struct jffs2_inode_cache * jffs2_get_inode_cache_next( struct jffs2_sb_info * c, uint32_t * ino )
{
    struct jffs2_inode_cache * ret;
    uint32_t curIno;
    uint32_t ihash;

    curIno = *ino;
    ihash = curino % 128;

    ret = c->inode_cache_list[ihash];

    while( NULL != ret )
    {
        if( ret->ino >= curInfo )
        {
             goto findinode;
        }
        ret = ret ->next;
    }
    for( ihash = ihash + 1; ihash < 128; ihash ++ )
    {
        if( NULL != ( ret = c->inode_cache_list[ihash] ) )
            goto findinode;
    }
    return NULL;
findinode:
    if( ret->next )
    {
        *ino = ret->next->ino;
    } else
    {
        *ino = ihash + 1;
    }
   return ret;  
}




From enrico.benetti at bluewind.it  Fri Jun 28 11:03:40 2013
From: enrico.benetti at bluewind.it (enrico benetti)
Date: Fri, 28 Jun 2013 17:03:40 +0200
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <51CD9168.7000902@bluewind.it>
References: <51CBDF47.709@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>,
 <51CC3669.103@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>
 <51CD9168.7000902@bluewind.it>
Message-ID: <51CDA5CC.7010808@bluewind.it>


> Please note that I'm using a 'slow' device (M29EW), with a maximum
> sector erasure time of 4 secs, and this seems to stress asynchronous
> operations with ubifs and integck test.
>
> I'll go on with commit log analysis to check if this kind of issue is
> already solved/discussed.
>
Hi,
at least two commits for M29EW NOR chips within MTD repo...trying to 
merge and then check again.

E



From computersforpeace at gmail.com  Fri Jun 28 22:08:25 2013
From: computersforpeace at gmail.com (Brian Norris)
Date: Fri, 28 Jun 2013 19:08:25 -0700
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <51CD9168.7000902@bluewind.it>
References: <51CBDF47.709@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>
 <51CC3669.103@bluewind.it>
 <ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>
 <51CD9168.7000902@bluewind.it>
Message-ID: <CAN8TOE-+3tedAebiWMTAzEJfaBPs7pwWBuKkJpV9Cx1e402nnQ@mail.gmail.com>

(Adding Huang, who has also debugged (different) problems with this NOR driver)

Hi Enrico,

On Fri, Jun 28, 2013 at 6:36 AM, enrico benetti
<enrico.benetti at bluewind.it> wrote:
> [   20.391279] MTD do_write_buffer(): software timeout
> [   20.452081] UBI error: nor_erase_prepare: cannot invalidate PEB 25,
> write returned -5 read returned 2
>
> Digging the web, I've found several discussions on write-timeout with
> NOR devices
> (cfr.http://lists.infradead.org/pipermail/linux-mtd/2013-June/047177.html),
> but this seems not to be the root cause.

I'm curious: what makes you think this has a different root cause?

I'm still working on debugging the do_write_buffer timeout on my
systems. I'd recommend trying to increase the timeout in
do_write_buffer(), just to see if your kernel isn't waiting long
enough. (In my case, I can pretty well show that while the code *says*
it's waiting for a whole jiffy -- at least 1ms -- it is in fact
waiting less than that.)

I believe Huang's resolution for his problem was actually a problem
with the flash part itself.

Brian


From zhengun23 at 126.com  Sat Jun 29 07:53:14 2013
From: zhengun23 at 126.com (zhengjun)
Date: Sat, 29 Jun 2013 19:53:14 +0800 (CST)
Subject: [JFFS2] why use a very low-efficient method to check all the
 uncheked inode in garbage_collect_pass
Message-ID: <636196b6.8142.13f8fc7a9db.Coremail.zhengun23@126.com>

I encountered a problem with my linux system?uses jffs2 file system?
After scan all inode on the flash, a background thread ( garbage_collect_thread) is start? Before collecting,
it begins with checking crc of all inodes in inode_cache_list. But unluckly the checking work cost all most 3
minutes?It costs the 98% of all cpu resource.
I found that the time is wasted on finding out the valid inode_cache with specified inode id (c->checked_ino)?
checked_ino is counted from zero to c->higest_ino? 
In my system, there are 3000 files,but with higest_ino reached to 27262976?
(Because the old file is replaced by new file, by first delete then copy)?
So the most of time, jffs2_get_inode_cache can not find a valid inode with c->checked_ino?
So the useless search works wastes a lot of time.
why?
why use a increased  index to find each indoe_cache in inode_cache_list? but you never know which index is the valide ino.
The indode_cache_list is a hash table.
why not use a deep-first-search method to get each inode in hash table?
Just remember next valid ino in c->checked_ino.

Now I designed a new search method? It works much more efficiently.

Could you optimize these code for better work?  Thanks!

jffs2_garbage_collect_pass()
{
   ....
    if( c->unchecked_size )
    {
        ic = jffs2_get_inode_cache_next( c, & c->checked_ino );  // new search method

       if( !ic )
      {
         BUG();
      }
   }
....
}

struct jffs2_inode_cache * jffs2_get_inode_cache_next( struct jffs2_sb_info * c, uint32_t * ino )
{
    struct jffs2_inode_cache * ret;
    uint32_t curIno;
    uint32_t ihash;

    curIno = *ino;
    ihash = curino % 128;

    ret = c->inode_cache_list[ihash];

    while( NULL != ret )
    {
        if( ret->ino >= curInfo )
        {
             goto findinode;
        }
        ret = ret ->next;
    }
    for( ihash = ihash + 1; ihash < 128; ihash ++ )
    {
        if( NULL != ( ret = c->inode_cache_list[ihash] ) )
            goto findinode;
    }
    return NULL;
findinode:
    if( ret->next )
    {
        *ino = ret->next->ino;
    } else
    {
        *ino = ihash + 1;
    }
   return ret;  
}




From ezequiel.garcia at free-electrons.com  Sat Jun 29 10:17:49 2013
From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia)
Date: Sat, 29 Jun 2013 11:17:49 -0300
Subject: [PATCH 0/5] mtd: nand: Fixes and improvements on pxa3xx
In-Reply-To: <20130617110304.GA2624@localhost>
References: <1368530125-12959-1-git-send-email-elezegarcia@gmail.com>
 <51BEA455.2020605@compulab.co.il> <20130617110304.GA2624@localhost>
Message-ID: <20130629141748.GA2524@localhost>

Hi Artem,

On Mon, Jun 17, 2013 at 08:03:05AM -0300, Ezequiel Garcia wrote:
> Nikita, Igor:
> 
> On Mon, Jun 17, 2013 at 08:53:25AM +0300, Igor Grinberg wrote:
> > On 05/14/13 14:15, Ezequiel Garcia wrote:
> > > The Armada 370 and Armada XP SoC include a NAND controller (NFCv2) that
> > > is similar to the one in PXA SoC. Therefore, it should be possible to support
> > > Armada NAND using pxa3xx-nand driver.
> > > 
> > > While this effort is not ready yet, here is a set of patches that are needed
> > > for such work.
> > > 
> > > A small summary of the patches:
> > > 
> > >   * 1/5 is a fix for a 2-year regression that removed DMA support.
> > > 
> > >   * 2/5 and 3/5 are needed to build the driver on platforms other PXA.
> > > 
> > >   * 4/5 and 5/5 add ONFI-compliant device detection and are needed
> > >     to successfully probe newer flash devices.
> > > 
> > > Applies cleanly on top of l2-mtd.git.
> > > 
> > > Thanks!
> > > 
> > > Ezequiel Garcia (5):
> > >   mtd: nand: pxa3xx: Set info->use_dma properly
> > >   mtd: nand: pxa3xx: Use of_machine_is_compatible()
> > >   mtd: nand: pxa3xx: Fix MODULE_DEVICE_TABLE declaration
> > >   mtd: nand: pxa3xx: Add address support for READID command
> > >   mtd: nand: pxa3xx: Add support for Read parameter page command
> > 
> > tested on cm-x300, upstream 3.10-rc5 and no regressions seen.
> > 
> > Tested-by: Nikita Kiryanov <nikita at compulab.co.il>
> > Acked-by: Igor Grinberg <grinberg at compulab.co.il>
> > 
> 
> Thanks a lot for the review and the test!
> 
> Artem, do you think this could be queued for v3.11?
> 

I guess it's already too late to have this merged for v3.11, right?

Given this has Tested-by, Acked-by and Reviewed-by, I think it should
be ready to apply. If there's anything you want me to review,
just let me know.

Thanks!
-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com


From b32955 at freescale.com  Sun Jun 30 22:23:17 2013
From: b32955 at freescale.com (Huang Shijie)
Date: Mon, 1 Jul 2013 10:23:17 +0800
Subject: UBIFS: power cut test on 2.6.35 + NOR
In-Reply-To: <CAN8TOE-+3tedAebiWMTAzEJfaBPs7pwWBuKkJpV9Cx1e402nnQ@mail.gmail.com>
References: <51CBDF47.709@bluewind.it>	<ED3E0BCACD909541BA94A34C4A164D4C4FCA81FE@post.tritech.se>	<51CC3669.103@bluewind.it>	<ED3E0BCACD909541BA94A34C4A164D4C4FCA8354@post.tritech.se>	<51CD9168.7000902@bluewind.it>
 <CAN8TOE-+3tedAebiWMTAzEJfaBPs7pwWBuKkJpV9Cx1e402nnQ@mail.gmail.com>
Message-ID: <51D0E815.8080300@freescale.com>

? 2013?06?29? 10:08, Brian Norris ??:
> (Adding Huang, who has also debugged (different) problems with this NOR driver)
>
> Hi Enrico,
>
> On Fri, Jun 28, 2013 at 6:36 AM, enrico benetti
> <enrico.benetti at bluewind.it>  wrote:
>> [   20.391279] MTD do_write_buffer(): software timeout
>> [   20.452081] UBI error: nor_erase_prepare: cannot invalidate PEB 25,
>> write returned -5 read returned 2
>>
>> Digging the web, I've found several discussions on write-timeout with
>> NOR devices
>> (cfr.http://lists.infradead.org/pipermail/linux-mtd/2013-June/047177.html),
>> but this seems not to be the root cause.
> I'm curious: what makes you think this has a different root cause?
>
> I'm still working on debugging the do_write_buffer timeout on my
> systems. I'd recommend trying to increase the timeout in
> do_write_buffer(), just to see if your kernel isn't waiting long
> enough. (In my case, I can pretty well show that while the code *says*
> it's waiting for a whole jiffy -- at least 1ms -- it is in fact
> waiting less than that.)
>
> I believe Huang's resolution for his problem was actually a problem
> with the flash part itself.
yes.
For my timeout, Micron confirmed that there is a silicon bug in this 
type of NOR.


thanks
Huang Shijie




