Skip to contentSkip to conversation

OMAP NAND redux

PATCH Charles Manning 2 participants 2 messages Dec 16, 2010 – Dec 29, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

Hello All

Over the last while I have been working on getting ubifs working on omap3530 using 16-bit NAND with the latest 2.6.37 prefetch code. This is basically a tweaked Overo kernel.

Here is what I found:

After initial exploration I found that there were three problem:

* ECC bytes not being read correctly during sub-page reads.
* Disabling prefetch meant that the flash was not being read at all.
* NAND access seems to have slowed down significantly.

Both these boiled down to one root cause. After the prefetch changes, nand->IO_ADDR_R is set to an address that only works within the context of the prefetch code. It no longer works if prefetch is disabled. Execution of:
static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd->priv;

        ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
} 

Even if prefetch is enabled, subpage reads that are not 32-bit aligned call the above function which means the ECC does not read correctly - resulting in ECC errors.

I managed to work around this by applying the following patch to force all buffer reads to u32 alignment:

drivers/mtd/nand/omap2.c +0 -0
@@ -245,6 +245,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd, 

u_char *buf, int len)

        int ret = 0;
        u32 *p = (u32 *)buf;

+ /* u32 align the buffer and read */
+ /* NB: This assumes the buf ptr can be aligned *down* which is a
valid.
+ * Assumption when dealing with ecc buffers etc.
+ */
+ u32 addr = (u32)p;
+

+       int diff = addr & 3;
+       addr -= diff;
+       len += diff;
+       len = (len + 3) & ~3;
+       p = (u32 *)addr;
+
        /* take care of subpage reads */
        if (len % 4) {
                if (info->nand.options & NAND_BUSWIDTH_16)

Yeah I know that is ugly, but it works!

Prefetch is enabled, dma is disabled. ECC is done in software.

OK, that gives me a working UBIFS, but I found something else...

NAND access has got way, way slower since 2.6.34.

I created a 2MB file foo then do the following:

sync; date; cp foo bar; sync; date

In 2.6.34 the time between the two dates was 3 seconds. In 2.6.37 this now takes 14 seconds!

Now question time:

1) How well has the prefetch code been tested?
2) Does it work with prefetch disabled?
3) Has it been performance tested?
4) What should the value in nand->IO_ADDR_R be?

Thanks

Charles

#1 lore raw
Quoted 37 lines

-----Original Message-----
From: Charles Manning [mailto:[email protected]]
Sent: Friday, December 17, 2010 3:31 AM
To: [email protected]
Cc: Ghorai, Sukumar; Grazvydas Ignotas
Subject: OMAP NAND redux

Hello All

Over the last while I have been working on getting ubifs working on omap3530
using 16-bit NAND with the latest 2.6.37 prefetch code. This is basically a
tweaked Overo kernel.

Here is what I found:

After initial exploration I found that there were three problem:

* ECC bytes not being read correctly during sub-page reads.
* Disabling prefetch meant that the flash was not being read at all.
* NAND access seems to have slowed down significantly.

Both these boiled down to one root cause. After the prefetch changes, nand->IO_ADDR_R is set to an address that only works within the context of the prefetch code. It no longer works if prefetch is disabled. Execution of:
static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd->priv;

        ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
}
Quoted 5 lines

Even if prefetch is enabled, subpage reads that are not 32-bit aligned call
the above function which means the ECC does not read correctly - resulting in
ECC errors.

[Ghorai] please give a try with CONFIG_MTD_NAND_OMAP_HWECC enable; i.e. NAND_ECC_HW; by this I did not see this issue

Quoted 27 lines

I managed to work around this by applying the following patch to force all buffer reads to u32 alignment:

drivers/mtd/nand/omap2.c +2 -0
@@ -245,6 +245,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd,
 u_char *buf, int len)
        int ret = 0;
        u32 *p = (u32 *)buf;
 
+       /* u32 align the buffer and read */
+       /* NB: This assumes the buf ptr can be aligned *down* which is a

valid.

drivers/mtd/nand/omap2.c +10 -0
+        * Assumption when dealing with ecc buffers etc.
+        */
+       u32 addr = (u32)p;
+
+       int diff = addr & 3;
+       addr -= diff;
+       len += diff;
+       len = (len + 3) & ~3;
+       p = (u32 *)addr;
+
        /* take care of subpage reads */
        if (len % 4) {
                if (info->nand.options & NAND_BUSWIDTH_16)
Quoted 3 lines

Yeah I know that is ugly, but it works!

Prefetch is enabled, dma is disabled. ECC is done in software.

[Ghorai] please give a try with CONFIG_MTD_NAND_OMAP_HWECC enable

Quoted 8 lines

OK, that gives me a working UBIFS, but I found something else...

NAND access has got way, way slower since 2.6.34.

I created a 2MB file foo then do the following:

sync; date; cp foo bar; sync; date

Quoted 7 lines

In 2.6.34 the time between the two dates was 3 seconds. In 2.6.37 this now takes 14 seconds!

Now question time:

1) How well has the prefetch code been tested?

[Ghorai] yes, its enable by default even in 2.6.34 onwards And many omap products using this.

Quoted 1 line

2) Does it work with prefetch disabled?

[Ghorai] yes.

Quoted 1 line

3) Has it been performance tested?

[Ghorai] yes. I did not remember the numbers.

Quoted 1 line

4) What should the value in nand->IO_ADDR_R be?

[Ghorai] this could be the same as IO_ADDR_W
And you can refer Section in TRM: Global Memory Space Mapping

Quoted 5 lines

Thanks

Charles