aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorBaruch Siach <baruch@tkos.co.il>2015-05-13 11:17:38 +0300
committerBrian Norris <computersforpeace@gmail.com>2015-05-20 15:29:53 -0700
commit0d17fc3e998357469700e0782d253c31a6997505 (patch)
treebabdc74ddc3c407f843ebeebe608b1a45f2e8c6e /drivers/mtd
parentmtd: mxc_nand: limit the size of used oob (diff)
downloadlinux-dev-0d17fc3e998357469700e0782d253c31a6997505.tar.xz
linux-dev-0d17fc3e998357469700e0782d253c31a6997505.zip
mtd: mxc_nand: fix truncate of unaligned oob copying
Copy to/from oob io area might not be aligned to 4 bytes. When 8 bit ECC is used, the buffer size is 26. Add memcpy16_{to,from}io, and use them to avoid truncating the buffer. Prefer memcpy32_{to,from}io when the buffer is properly aligned for better performance. Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Baruch Siach <baruch@tkos.co.il> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/mxc_nand.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index ceeb61cad7d4..260d77d5cc21 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -281,12 +281,44 @@ static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
*t++ = __raw_readl(s++);
}
+static void memcpy16_fromio(void *trg, const void __iomem *src, size_t size)
+{
+ int i;
+ u16 *t = trg;
+ const __iomem u16 *s = src;
+
+ /* We assume that src (IO) is always 32bit aligned */
+ if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
+ memcpy32_fromio(trg, src, size);
+ return;
+ }
+
+ for (i = 0; i < (size >> 1); i++)
+ *t++ = __raw_readw(s++);
+}
+
static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
{
/* __iowrite32_copy use 32bit size values so divide by 4 */
__iowrite32_copy(trg, src, size / 4);
}
+static void memcpy16_toio(void __iomem *trg, const void *src, int size)
+{
+ int i;
+ __iomem u16 *t = trg;
+ const u16 *s = src;
+
+ /* We assume that trg (IO) is always 32bit aligned */
+ if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
+ memcpy32_toio(trg, src, size);
+ return;
+ }
+
+ for (i = 0; i < (size >> 1); i++)
+ __raw_writew(*s++, t++);
+}
+
static int check_int_v3(struct mxc_nand_host *host)
{
uint32_t tmp;
@@ -832,22 +864,22 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
if (bfrom) {
for (i = 0; i < num_chunks - 1; i++)
- memcpy32_fromio(d + i * oob_chunk_size,
+ memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
oob_chunk_size);
/* the last chunk */
- memcpy32_fromio(d + i * oob_chunk_size,
+ memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
host->used_oobsize - i * oob_chunk_size);
} else {
for (i = 0; i < num_chunks - 1; i++)
- memcpy32_toio(&s[i * sparebuf_size],
+ memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
oob_chunk_size);
/* the last chunk */
- memcpy32_toio(&s[oob_chunk_size * sparebuf_size],
+ memcpy16_toio(&s[oob_chunk_size * sparebuf_size],
&d[i * oob_chunk_size],
host->used_oobsize - i * oob_chunk_size);
}