@@ -775,7 +775,7 @@ static struct nand_bbt_descr sharpsl_akita_bbt = {
.pattern = scan_ff_pattern
};
-static struct nand_ecclayout akita_oobinfo = {
+static struct nand_ecclayout_l akita_oobinfo = {
.eccbytes = 24,
.eccpos = {
0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
@@ -70,7 +70,7 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
if (set->ecc_layout) {
ptr = kmemdup(set->ecc_layout,
- sizeof(struct nand_ecclayout), GFP_KERNEL);
+ sizeof(*set->ecc_layout), GFP_KERNEL);
set->ecc_layout = ptr;
if (!ptr)
@@ -38,7 +38,7 @@ struct s3c2410_nand_set {
char *name;
int *nr_map;
struct mtd_partition *partitions;
- struct nand_ecclayout *ecc_layout;
+ struct nand_ecclayout_l *ecc_layout;
};
struct s3c2410_platform_nand {
@@ -464,6 +464,39 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
return ret;
}
+/*
+ * Copies (and truncates, if necessary) data from the larger struct,
+ * nand_ecclayout_l, to the smaller, deprecated layout struct,
+ * nand_ecclayout. This is necessary only to suppport the deprecated
+ * API ioctl ECCGETLAYOUT while allowing all new functionality to use
+ * nand_ecclayout_l flexibly (i.e. the struct may change size in new
+ * releases without requiring major rewrites).
+ */
+static int shrink_ecclayout(const struct nand_ecclayout_l *from,
+ struct nand_ecclayout *to)
+{
+ int i;
+
+ if (!from || !to)
+ return -EINVAL;
+
+ memset(to, 0, sizeof(*to));
+
+ to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES_OLD);
+ for (i = 0; i < to->eccbytes; i++)
+ to->eccpos[i] = from->eccpos[i];
+
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
+ if (from->oobfree[i].length == 0 &&
+ from->oobfree[i].offset == 0)
+ break;
+ to->oobavail += from->oobfree[i].length;
+ to->oobfree[i] = from->oobfree[i];
+ }
+
+ return 0;
+}
+
static int mtd_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
@@ -800,14 +833,23 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
}
#endif
+ /* This ioctl is being deprecated - it truncates the ecc layout */
case ECCGETLAYOUT:
{
+ struct nand_ecclayout *usrlay;
+
if (!mtd->ecclayout)
return -EOPNOTSUPP;
- if (copy_to_user(argp, mtd->ecclayout,
- sizeof(struct nand_ecclayout)))
- return -EFAULT;
+ usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
+ if (!usrlay)
+ return -ENOMEM;
+
+ shrink_ecclayout(mtd->ecclayout, usrlay);
+
+ if (copy_to_user(argp, usrlay, sizeof(struct nand_ecclayout)))
+ ret = -EFAULT;
+ kfree(usrlay);
break;
}
@@ -64,7 +64,7 @@ module_param(on_flash_bbt, int, 0);
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
*/
-static struct nand_ecclayout atmel_oobinfo_large = {
+static struct nand_ecclayout_l atmel_oobinfo_large = {
.eccbytes = 4,
.eccpos = {60, 61, 62, 63},
.oobfree = {
@@ -77,7 +77,7 @@ static struct nand_ecclayout atmel_oobinfo_large = {
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
*/
-static struct nand_ecclayout atmel_oobinfo_small = {
+static struct nand_ecclayout_l atmel_oobinfo_small = {
.eccbytes = 4,
.eccpos = {0, 1, 2, 3},
.oobfree = {
@@ -32,7 +32,7 @@ static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
** nand_hw_eccoob
** New oob placement block for use with hardware ecc generation.
*/
-static struct nand_ecclayout nand_hw_eccoob_512 = {
+static struct nand_ecclayout_l nand_hw_eccoob_512 = {
/* Reserve 5 for BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 3)
@@ -48,7 +48,7 @@ static struct nand_ecclayout nand_hw_eccoob_512 = {
** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
** except the BI is at byte 0.
*/
-static struct nand_ecclayout nand_hw_eccoob_2048 = {
+static struct nand_ecclayout_l nand_hw_eccoob_2048 = {
/* Reserve 0 as BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 10)
@@ -69,7 +69,7 @@ static struct nand_ecclayout nand_hw_eccoob_2048 = {
/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
* except the BI is at byte 0. */
-static struct nand_ecclayout nand_hw_eccoob_4096 = {
+static struct nand_ecclayout_l nand_hw_eccoob_4096 = {
/* Reserve 0 as BI indicator */
.oobfree = {
#if (NAND_ECC_NUM_BYTES > 10)
@@ -119,7 +119,7 @@ static struct nand_bbt_descr bootrom_bbt = {
.pattern = bbt_pattern,
};
-static struct nand_ecclayout bootrom_ecclayout = {
+static struct nand_ecclayout_l bootrom_ecclayout = {
.eccbytes = 24,
.eccpos = {
0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2,
@@ -457,7 +457,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static struct nand_ecclayout cafe_oobinfo_2048 = {
+static struct nand_ecclayout_l cafe_oobinfo_2048 = {
.eccbytes = 14,
.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
.oobfree = {{14, 50}}
@@ -492,7 +492,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
.pattern = cafe_mirror_pattern_2048
};
-static struct nand_ecclayout cafe_oobinfo_512 = {
+static struct nand_ecclayout_l cafe_oobinfo_512 = {
.eccbytes = 14,
.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
.oobfree = {{14, 2}}
@@ -55,7 +55,7 @@
struct davinci_nand_info {
struct mtd_info mtd;
struct nand_chip chip;
- struct nand_ecclayout ecclayout;
+ struct nand_ecclayout_l ecclayout;
struct device *dev;
struct clk *clk;
@@ -514,7 +514,7 @@ static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info)
* ten ECC bytes plus the manufacturer's bad block marker byte, and
* and not overlapping the default BBT markers.
*/
-static struct nand_ecclayout hwecc4_small __initconst = {
+static struct nand_ecclayout_l hwecc4_small __initconst = {
.eccbytes = 10,
.eccpos = { 0, 1, 2, 3, 4,
/* offset 5 holds the badblock marker */
@@ -530,7 +530,7 @@ static struct nand_ecclayout hwecc4_small __initconst = {
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers.
*/
-static struct nand_ecclayout hwecc4_2048 __initconst = {
+static struct nand_ecclayout_l hwecc4_2048 __initconst = {
.eccbytes = 40,
.eccpos = {
/* at the end of spare sector */
@@ -745,10 +745,13 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
}
/* 4KiB page chips are not yet supported. The eccpos from
- * nand_ecclayout cannot hold 80 bytes and change to eccpos[]
+ * nand_ecclayout_l cannot hold 80 bytes and change to eccpos[]
* breaks userspace ioctl interface with mtd-utils. Once we
* resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used
* for the 4KiB page chips.
+ *
+ * TODO: Note that nand_ecclayout_l has been introduced to
+ * replace nand_ecclayout and can hold plenty of OOB entries.
*/
dev_warn(&pdev->dev, "no 4-bit ECC support yet "
"for 4KiB-page NAND\n");
@@ -1051,7 +1051,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
* safer. The only problem with it is that any code that parses oobfree must
* be able to handle out-of-order segments.
*/
-static struct nand_ecclayout doc200x_oobinfo = {
+static struct nand_ecclayout_l doc200x_oobinfo = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 4, 5},
.oobfree = {{8, 8}, {6, 2}}
@@ -85,28 +85,28 @@ struct fsl_elbc_ctrl {
/* These map to the positions used by the FCM hardware ECC generator */
/* Small Page FLASH with FMR[ECCM] = 0 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
+static struct nand_ecclayout_l fsl_elbc_oob_sp_eccm0 = {
.eccbytes = 3,
.eccpos = {6, 7, 8},
.oobfree = { {0, 5}, {9, 7} },
};
/* Small Page FLASH with FMR[ECCM] = 1 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
+static struct nand_ecclayout_l fsl_elbc_oob_sp_eccm1 = {
.eccbytes = 3,
.eccpos = {8, 9, 10},
.oobfree = { {0, 5}, {6, 2}, {11, 5} },
};
/* Large Page FLASH with FMR[ECCM] = 0 */
-static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
+static struct nand_ecclayout_l fsl_elbc_oob_lp_eccm0 = {
.eccbytes = 12,
.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
};
/* Large Page FLASH with FMR[ECCM] = 1 */
-static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
+static struct nand_ecclayout_l fsl_elbc_oob_lp_eccm1 = {
.eccbytes = 12,
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
@@ -165,13 +165,13 @@ struct mxc_nand_host {
};
/* OOB placement block for use with hardware ecc generation */
-static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
+static struct nand_ecclayout_l nandv1_hw_eccoob_smallpage = {
.eccbytes = 5,
.eccpos = {6, 7, 8, 9, 10},
.oobfree = {{0, 5}, {12, 4}, }
};
-static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
+static struct nand_ecclayout_l nandv1_hw_eccoob_largepage = {
.eccbytes = 20,
.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
@@ -179,7 +179,7 @@ static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
};
/* OOB description for 512 byte pages with 16 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
+static struct nand_ecclayout_l nandv2_hw_eccoob_smallpage = {
.eccbytes = 1 * 9,
.eccpos = {
7, 8, 9, 10, 11, 12, 13, 14, 15
@@ -190,7 +190,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
};
/* OOB description for 2048 byte pages with 64 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
+static struct nand_ecclayout_l nandv2_hw_eccoob_largepage = {
.eccbytes = 4 * 9,
.eccpos = {
7, 8, 9, 10, 11, 12, 13, 14, 15,
@@ -956,7 +956,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
struct mxc_nand_host *host;
struct resource *res;
int err = 0, nr_parts = 0;
- struct nand_ecclayout *oob_smallpage, *oob_largepage;
+ struct nand_ecclayout_l *oob_smallpage, *oob_largepage;
/* Allocate memory for MTD device structure and private data */
host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
@@ -53,7 +53,7 @@
#endif
/* Define default oob placement schemes for large and small page devices */
-static struct nand_ecclayout nand_oob_8 = {
+static struct nand_ecclayout_l nand_oob_8 = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
.oobfree = {
@@ -63,7 +63,7 @@ static struct nand_ecclayout nand_oob_8 = {
.length = 2}}
};
-static struct nand_ecclayout nand_oob_16 = {
+static struct nand_ecclayout_l nand_oob_16 = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = {
@@ -71,7 +71,7 @@ static struct nand_ecclayout nand_oob_16 = {
. length = 8}}
};
-static struct nand_ecclayout nand_oob_64 = {
+static struct nand_ecclayout_l nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
@@ -82,7 +82,7 @@ static struct nand_ecclayout nand_oob_64 = {
.length = 38}}
};
-static struct nand_ecclayout nand_oob_128 = {
+static struct nand_ecclayout_l nand_oob_128 = {
.eccbytes = 48,
.eccpos = {
80, 81, 82, 83, 84, 85, 86, 87,
@@ -45,7 +45,7 @@ struct nomadik_nand_host {
struct nand_bbt_descr *bbt_desc;
};
-static struct nand_ecclayout nomadik_ecc_layout = {
+static struct nand_ecclayout_l nomadik_ecc_layout = {
.eccbytes = 3 * 4,
.eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
0x02, 0x03, 0x04,
@@ -1159,13 +1159,13 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
return 0;
}
-static struct nand_ecclayout hw_smallpage_ecclayout = {
+static struct nand_ecclayout_l hw_smallpage_ecclayout = {
.eccbytes = 6,
.eccpos = {8, 9, 10, 11, 12, 13 },
.oobfree = { {2, 6} }
};
-static struct nand_ecclayout hw_largepage_ecclayout = {
+static struct nand_ecclayout_l hw_largepage_ecclayout = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
@@ -141,7 +141,7 @@ static struct rs_control *rs_decoder;
/*
* hardware specific Out Of Band information
*/
-static struct nand_ecclayout rtc_from4_nand_oobinfo = {
+static struct nand_ecclayout_l rtc_from4_nand_oobinfo = {
.eccbytes = 32,
.eccpos = {
0, 1, 2, 3, 4, 5, 6, 7,
@@ -64,7 +64,7 @@ static const int clock_stop = 0;
/* new oob placement block for use with hardware ecc generation
*/
-static struct nand_ecclayout nand_hw_eccoob = {
+static struct nand_ecclayout_l nand_hw_eccoob = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
.oobfree = {{8, 8}}
@@ -33,7 +33,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/sh_flctl.h>
-static struct nand_ecclayout flctl_4secc_oob_16 = {
+static struct nand_ecclayout_l flctl_4secc_oob_16 = {
.eccbytes = 10,
.eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
.oobfree = {
@@ -41,7 +41,7 @@ static struct nand_ecclayout flctl_4secc_oob_16 = {
. length = 4} },
};
-static struct nand_ecclayout flctl_4secc_oob_64 = {
+static struct nand_ecclayout_l flctl_4secc_oob_64 = {
.eccbytes = 10,
.eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
.oobfree = {
@@ -69,7 +69,7 @@ MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP"
* onenand_oob_128 - oob info for Flex-Onenand with 4KB page
* For now, we expose only 64 out of 80 ecc bytes
*/
-static struct nand_ecclayout onenand_oob_128 = {
+static struct nand_ecclayout_l onenand_oob_128 = {
.eccbytes = 64,
.eccpos = {
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
@@ -89,7 +89,7 @@ static struct nand_ecclayout onenand_oob_128 = {
/**
* onenand_oob_64 - oob info for large (2KB) page
*/
-static struct nand_ecclayout onenand_oob_64 = {
+static struct nand_ecclayout_l onenand_oob_64 = {
.eccbytes = 20,
.eccpos = {
8, 9, 10, 11, 12,
@@ -106,7 +106,7 @@ static struct nand_ecclayout onenand_oob_64 = {
/**
* onenand_oob_32 - oob info for middle (1KB) page
*/
-static struct nand_ecclayout onenand_oob_32 = {
+static struct nand_ecclayout_l onenand_oob_32 = {
.eccbytes = 10,
.eccpos = {
8, 9, 10, 11, 12,
@@ -1145,7 +1145,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{
- struct nand_ecclayout *oinfo = c->mtd->ecclayout;
+ struct nand_ecclayout_l *oinfo = c->mtd->ecclayout;
if (!c->mtd->oobsize)
return 0;
@@ -44,7 +44,7 @@ struct INFTLrecord {
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
- struct nand_ecclayout oobinfo;
+ struct nand_ecclayout_l oobinfo;
};
int INFTL_mount(struct INFTLrecord *s);
@@ -98,6 +98,21 @@ struct mtd_oob_ops {
uint8_t *oobbuf;
};
+#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
+#define MTD_MAX_ECCPOS_ENTRIES_LARGE 448
+#define MTD_MAX_ECCPOS_ENTRIES_OLD 64 /* Previous maximum */
+/*
+ * Correct ECC layout control structure. This replaces old nand_ecclayout
+ * that is exported via ECCGETLAYOUT ioctll. It should be expandable in the
+ * future simply by the above macros.
+ */
+struct nand_ecclayout_l {
+ __u32 eccbytes;
+ __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
+ __u32 oobavail;
+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
+};
+
struct mtd_info {
u_char type;
uint32_t flags;
@@ -135,7 +150,7 @@ struct mtd_info {
int index;
/* ecc layout structure pointer - read only ! */
- struct nand_ecclayout *ecclayout;
+ struct nand_ecclayout_l *ecclayout;
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
@@ -270,7 +270,7 @@ struct nand_ecc_ctrl {
int total;
int prepad;
int postpad;
- struct nand_ecclayout *layout;
+ struct nand_ecclayout_l *layout;
void (*hwctl)(struct mtd_info *mtd, int mode);
int (*calculate)(struct mtd_info *mtd,
const uint8_t *dat,
@@ -415,7 +415,7 @@ struct nand_chip {
uint8_t *oob_poi;
struct nand_hw_control *controller;
- struct nand_ecclayout *ecclayout;
+ struct nand_ecclayout_l *ecclayout;
struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
@@ -506,7 +506,7 @@ struct platform_nand_chip {
int chip_offset;
int nr_partitions;
struct mtd_partition *partitions;
- struct nand_ecclayout *ecclayout;
+ struct nand_ecclayout_l *ecclayout;
int chip_delay;
unsigned int options;
const char **part_probe_types;
@@ -35,7 +35,7 @@ struct NFTLrecord {
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
- struct nand_ecclayout oobinfo;
+ struct nand_ecclayout_l oobinfo;
};
int NFTL_mount(struct NFTLrecord *s);
@@ -132,7 +132,7 @@ struct onenand_chip {
#endif
int subpagesize;
- struct nand_ecclayout *ecclayout;
+ struct nand_ecclayout_l *ecclayout;
void *bbm;
@@ -39,7 +39,7 @@ struct mtd_partition {
uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
- struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
+ struct nand_ecclayout_l *ecclayout; /* out of band layout for this partition (NAND only) */
};
#define MTDPART_OFS_NXTBLK (-2)
@@ -14,7 +14,7 @@
struct sharpsl_nand_platform_data {
struct nand_bbt_descr *badblock_pattern;
- struct nand_ecclayout *ecc_layout;
+ struct nand_ecclayout_l *ecc_layout;
struct mtd_partition *partitions;
unsigned int nr_partitions;
};