aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2010-08-24 21:12:00 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-10-24 18:37:24 -0400
commitcc26c3cd3d1cf40a07f2b19ac4c53d517bee52a5 (patch)
tree664c422944f780a1cc99f872714eeb339efef7ef
parentf4a2da0cd522a3b805ff2386c14912945bf990c7 (diff)
mtd: nand: expand nand_ecc_layout, deprecate ioctl ECCGETLAYOUT
struct nand_ecclayout is too small for many new chips; OOB regions can be as large as 448 bytes and may increase more in the future. Thus, copying that struct to user-space with the ECCGETLAYOUT ioctl is not a good idea; the ioctl would have to be updated every time there's a change to the current largest size. Instead, the old nand_ecclayout is renamed to nand_ecclayout_user and a new struct nand_ecclayout is created that can accomodate larger sizes and expand without affecting the user-space. struct nand_ecclayout can still be used in board drivers without modification -- at least for now. A new function is provided to convert from the new to the old in order to allow the deprecated ioctl to continue to work with truncated data. Perhaps the ioctl, the conversion process, and the struct nand_ecclayout_user can be removed altogether in the future. Note: There are comments in nand/davinci_nand.c::nand_davinci_probe() regarding this issue; this driver (and maybe others) can be updated to account for extra space. All kernel drivers can use the expanded nand_ecclayout as a drop-in replacement and ignore its benefits. Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/mtdchar.c48
-rw-r--r--drivers/mtd/nand/davinci_nand.c3
-rw-r--r--include/linux/mtd/mtd.h15
-rw-r--r--include/linux/mtd/partitions.h2
-rw-r--r--include/mtd/mtd-abi.h4
-rw-r--r--include/mtd/mtd-user.h2
6 files changed, 67 insertions, 7 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index a825002123c8..24d35ba62b84 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -477,6 +477,39 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
477 return ret; 477 return ret;
478} 478}
479 479
480/*
481 * Copies (and truncates, if necessary) data from the larger struct,
482 * nand_ecclayout, to the smaller, deprecated layout struct,
483 * nand_ecclayout_user. This is necessary only to suppport the deprecated
484 * API ioctl ECCGETLAYOUT while allowing all new functionality to use
485 * nand_ecclayout flexibly (i.e. the struct may change size in new
486 * releases without requiring major rewrites).
487 */
488static int shrink_ecclayout(const struct nand_ecclayout *from,
489 struct nand_ecclayout_user *to)
490{
491 int i;
492
493 if (!from || !to)
494 return -EINVAL;
495
496 memset(to, 0, sizeof(*to));
497
498 to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES_OLD);
499 for (i = 0; i < to->eccbytes; i++)
500 to->eccpos[i] = from->eccpos[i];
501
502 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
503 if (from->oobfree[i].length == 0 &&
504 from->oobfree[i].offset == 0)
505 break;
506 to->oobavail += from->oobfree[i].length;
507 to->oobfree[i] = from->oobfree[i];
508 }
509
510 return 0;
511}
512
480static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) 513static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
481{ 514{
482 struct mtd_file_info *mfi = file->private_data; 515 struct mtd_file_info *mfi = file->private_data;
@@ -812,14 +845,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
812 } 845 }
813#endif 846#endif
814 847
848 /* This ioctl is being deprecated - it truncates the ecc layout */
815 case ECCGETLAYOUT: 849 case ECCGETLAYOUT:
816 { 850 {
851 struct nand_ecclayout_user *usrlay;
852
817 if (!mtd->ecclayout) 853 if (!mtd->ecclayout)
818 return -EOPNOTSUPP; 854 return -EOPNOTSUPP;
819 855
820 if (copy_to_user(argp, mtd->ecclayout, 856 usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
821 sizeof(struct nand_ecclayout))) 857 if (!usrlay)
822 return -EFAULT; 858 return -ENOMEM;
859
860 shrink_ecclayout(mtd->ecclayout, usrlay);
861
862 if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
863 ret = -EFAULT;
864 kfree(usrlay);
823 break; 865 break;
824 } 866 }
825 867
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 2ac7367afe77..70698e86e437 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -749,6 +749,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
749 * breaks userspace ioctl interface with mtd-utils. Once we 749 * breaks userspace ioctl interface with mtd-utils. Once we
750 * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used 750 * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used
751 * for the 4KiB page chips. 751 * for the 4KiB page chips.
752 *
753 * TODO: Note that nand_ecclayout has now been expanded and can
754 * hold plenty of OOB entries.
752 */ 755 */
753 dev_warn(&pdev->dev, "no 4-bit ECC support yet " 756 dev_warn(&pdev->dev, "no 4-bit ECC support yet "
754 "for 4KiB-page NAND\n"); 757 "for 4KiB-page NAND\n");
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 8485e42a9b09..03a1e954c586 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -110,6 +110,21 @@ struct mtd_oob_ops {
110 uint8_t *oobbuf; 110 uint8_t *oobbuf;
111}; 111};
112 112
113#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
114#define MTD_MAX_ECCPOS_ENTRIES_LARGE 448
115#define MTD_MAX_ECCPOS_ENTRIES_OLD 64 /* Previous maximum */
116/*
117 * Correct ECC layout control structure. This replaces old nand_ecclayout
118 * (mtd-abi.h) that is exported via ECCGETLAYOUT ioctl. It should be expandable
119 * in the future simply by the above macros.
120 */
121struct nand_ecclayout {
122 __u32 eccbytes;
123 __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
124 __u32 oobavail;
125 struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
126};
127
113struct mtd_info { 128struct mtd_info {
114 u_char type; 129 u_char type;
115 uint32_t flags; 130 uint32_t flags;
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 274b6196091d..930c8ac198db 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -39,7 +39,7 @@ struct mtd_partition {
39 uint64_t size; /* partition size */ 39 uint64_t size; /* partition size */
40 uint64_t offset; /* offset within the master MTD space */ 40 uint64_t offset; /* offset within the master MTD space */
41 uint32_t mask_flags; /* master MTD flags to mask out for this partition */ 41 uint32_t mask_flags; /* master MTD flags to mask out for this partition */
42 struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ 42 struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */
43}; 43};
44 44
45#define MTDPART_OFS_NXTBLK (-2) 45#define MTDPART_OFS_NXTBLK (-2)
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 4debb4514634..5bce08384345 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -119,7 +119,7 @@ struct otp_info {
119#define OTPGETREGIONCOUNT _IOW('M', 14, int) 119#define OTPGETREGIONCOUNT _IOW('M', 14, int)
120#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) 120#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
121#define OTPLOCK _IOR('M', 16, struct otp_info) 121#define OTPLOCK _IOR('M', 16, struct otp_info)
122#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) 122#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user)
123#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) 123#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
124#define MTDFILEMODE _IO('M', 19) 124#define MTDFILEMODE _IO('M', 19)
125#define MEMERASE64 _IOW('M', 20, struct erase_info_user64) 125#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
@@ -148,7 +148,7 @@ struct nand_oobfree {
148 * ECC layout control structure. Exported to userspace for 148 * ECC layout control structure. Exported to userspace for
149 * diagnosis and to allow creation of raw images 149 * diagnosis and to allow creation of raw images
150 */ 150 */
151struct nand_ecclayout { 151struct nand_ecclayout_user {
152 __u32 eccbytes; 152 __u32 eccbytes;
153 __u32 eccpos[64]; 153 __u32 eccpos[64];
154 __u32 oobavail; 154 __u32 oobavail;
diff --git a/include/mtd/mtd-user.h b/include/mtd/mtd-user.h
index aa3c2f86a913..83327c808c86 100644
--- a/include/mtd/mtd-user.h
+++ b/include/mtd/mtd-user.h
@@ -29,6 +29,6 @@ typedef struct mtd_info_user mtd_info_t;
29typedef struct erase_info_user erase_info_t; 29typedef struct erase_info_user erase_info_t;
30typedef struct region_info_user region_info_t; 30typedef struct region_info_user region_info_t;
31typedef struct nand_oobinfo nand_oobinfo_t; 31typedef struct nand_oobinfo nand_oobinfo_t;
32typedef struct nand_ecclayout nand_ecclayout_t; 32typedef struct nand_ecclayout_user nand_ecclayout_t;
33 33
34#endif /* __MTD_USER_H__ */ 34#endif /* __MTD_USER_H__ */