xref: /openbmc/linux/drivers/mtd/mtdcore.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
1fd534e9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Core registration and callback routines for MTD
41da177e4SLinus Torvalds  * drivers and users.
51da177e4SLinus Torvalds  *
6a1452a37SDavid Woodhouse  * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
7a1452a37SDavid Woodhouse  * Copyright © 2006      Red Hat UK Limited
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/ptrace.h>
13447d9bd8SAlexey Dobriyan #include <linux/seq_file.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/timer.h>
161da177e4SLinus Torvalds #include <linux/major.h>
171da177e4SLinus Torvalds #include <linux/fs.h>
187799308fSArtem Bityutskiy #include <linux/err.h>
191da177e4SLinus Torvalds #include <linux/ioctl.h>
201da177e4SLinus Torvalds #include <linux/init.h>
21215a02fdSBrian Norris #include <linux/of.h>
221da177e4SLinus Torvalds #include <linux/proc_fs.h>
23b520e412SBen Hutchings #include <linux/idr.h>
24a33eb6b9SJörn Engel #include <linux/backing-dev.h>
2505d71b46STejun Heo #include <linux/gfp.h>
263b270facSLinus Walleij #include <linux/random.h>
270d01ff25SDavid Howells #include <linux/slab.h>
283efe41beSBrian Norris #include <linux/reboot.h>
29fea728c0SEzequiel Garcia #include <linux/leds.h>
30e8e3edb9SMario Rugiero #include <linux/debugfs.h>
31c4dfa25aSAlban Bedel #include <linux/nvmem-provider.h>
3226422ac7SRafał Miłecki #include <linux/root_dev.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
35f5671ab3SJamie Iles #include <linux/mtd/partitions.h>
361da177e4SLinus Torvalds 
37356d70f1SBen Dooks #include "mtdcore.h"
38660685d9SArtem Bityutskiy 
39fa06052dSJan Kara struct backing_dev_info *mtd_bdi;
40356d70f1SBen Dooks 
4157b8045dSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP
4257b8045dSLars-Peter Clausen 
mtd_cls_suspend(struct device * dev)4357b8045dSLars-Peter Clausen static int mtd_cls_suspend(struct device *dev)
4457b8045dSLars-Peter Clausen {
4557b8045dSLars-Peter Clausen 	struct mtd_info *mtd = dev_get_drvdata(dev);
4657b8045dSLars-Peter Clausen 
4757b8045dSLars-Peter Clausen 	return mtd ? mtd_suspend(mtd) : 0;
4857b8045dSLars-Peter Clausen }
4957b8045dSLars-Peter Clausen 
mtd_cls_resume(struct device * dev)5057b8045dSLars-Peter Clausen static int mtd_cls_resume(struct device *dev)
5157b8045dSLars-Peter Clausen {
5257b8045dSLars-Peter Clausen 	struct mtd_info *mtd = dev_get_drvdata(dev);
5357b8045dSLars-Peter Clausen 
5457b8045dSLars-Peter Clausen 	if (mtd)
5557b8045dSLars-Peter Clausen 		mtd_resume(mtd);
5657b8045dSLars-Peter Clausen 	return 0;
5757b8045dSLars-Peter Clausen }
5857b8045dSLars-Peter Clausen 
5957b8045dSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(mtd_cls_pm_ops, mtd_cls_suspend, mtd_cls_resume);
6057b8045dSLars-Peter Clausen #define MTD_CLS_PM_OPS (&mtd_cls_pm_ops)
6157b8045dSLars-Peter Clausen #else
6257b8045dSLars-Peter Clausen #define MTD_CLS_PM_OPS NULL
6357b8045dSLars-Peter Clausen #endif
641f24b5a8SDavid Brownell 
6515bce40cSDavid Woodhouse static struct class mtd_class = {
6615bce40cSDavid Woodhouse 	.name = "mtd",
6757b8045dSLars-Peter Clausen 	.pm = MTD_CLS_PM_OPS,
6815bce40cSDavid Woodhouse };
691f24b5a8SDavid Brownell 
70b520e412SBen Hutchings static DEFINE_IDR(mtd_idr);
71b520e412SBen Hutchings 
721da177e4SLinus Torvalds /* These are exported solely for the purpose of mtd_blkdevs.c. You
731da177e4SLinus Torvalds    should not use them for _anything_ else */
7448b19268SIngo Molnar DEFINE_MUTEX(mtd_table_mutex);
751da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(mtd_table_mutex);
76b520e412SBen Hutchings 
__mtd_next_device(int i)77b520e412SBen Hutchings struct mtd_info *__mtd_next_device(int i)
78b520e412SBen Hutchings {
79b520e412SBen Hutchings 	return idr_get_next(&mtd_idr, &i);
80b520e412SBen Hutchings }
81b520e412SBen Hutchings EXPORT_SYMBOL_GPL(__mtd_next_device);
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static LIST_HEAD(mtd_notifiers);
841da177e4SLinus Torvalds 
851f24b5a8SDavid Brownell 
861f24b5a8SDavid Brownell #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
871f24b5a8SDavid Brownell 
881f24b5a8SDavid Brownell /* REVISIT once MTD uses the driver model better, whoever allocates
891f24b5a8SDavid Brownell  * the mtd_info will probably want to use the release() hook...
901f24b5a8SDavid Brownell  */
mtd_release(struct device * dev)911f24b5a8SDavid Brownell static void mtd_release(struct device *dev)
921f24b5a8SDavid Brownell {
935e472128SBrian Norris 	struct mtd_info *mtd = dev_get_drvdata(dev);
94d5de20a9SArtem Bityutskiy 	dev_t index = MTD_DEVT(mtd->index);
951f24b5a8SDavid Brownell 
96e9714c22SAlexander Usyskin 	idr_remove(&mtd_idr, mtd->index);
97e9714c22SAlexander Usyskin 	of_node_put(mtd_get_of_node(mtd));
98e9714c22SAlexander Usyskin 
9919bfa9ebSTomas Winkler 	if (mtd_is_partition(mtd))
10019bfa9ebSTomas Winkler 		release_mtd_partition(mtd);
10119bfa9ebSTomas Winkler 
1025e472128SBrian Norris 	/* remove /dev/mtdXro node */
10315bce40cSDavid Woodhouse 	device_destroy(&mtd_class, index + 1);
10415bce40cSDavid Woodhouse }
10515bce40cSDavid Woodhouse 
mtd_device_release(struct kref * kref)10619bfa9ebSTomas Winkler static void mtd_device_release(struct kref *kref)
10719bfa9ebSTomas Winkler {
10819bfa9ebSTomas Winkler 	struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
109e9714c22SAlexander Usyskin 	bool is_partition = mtd_is_partition(mtd);
11019bfa9ebSTomas Winkler 
11119bfa9ebSTomas Winkler 	debugfs_remove_recursive(mtd->dbg.dfs_dir);
11219bfa9ebSTomas Winkler 
11319bfa9ebSTomas Winkler 	/* Try to remove the NVMEM provider */
11419bfa9ebSTomas Winkler 	nvmem_unregister(mtd->nvmem);
11519bfa9ebSTomas Winkler 
11619bfa9ebSTomas Winkler 	device_unregister(&mtd->dev);
11719bfa9ebSTomas Winkler 
118e9714c22SAlexander Usyskin 	/*
119e9714c22SAlexander Usyskin 	 *  Clear dev so mtd can be safely re-registered later if desired.
120e9714c22SAlexander Usyskin 	 *  Should not be done for partition,
121e9714c22SAlexander Usyskin 	 *  as it was already destroyed in device_unregister().
122e9714c22SAlexander Usyskin 	 */
123e9714c22SAlexander Usyskin 	if (!is_partition)
12419bfa9ebSTomas Winkler 		memset(&mtd->dev, 0, sizeof(mtd->dev));
12519bfa9ebSTomas Winkler 
12619bfa9ebSTomas Winkler 	module_put(THIS_MODULE);
12719bfa9ebSTomas Winkler }
12819bfa9ebSTomas Winkler 
129b4e24863SZhen Lei #define MTD_DEVICE_ATTR_RO(name) \
130b4e24863SZhen Lei static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL)
131b4e24863SZhen Lei 
132b4e24863SZhen Lei #define MTD_DEVICE_ATTR_RW(name) \
133b4e24863SZhen Lei static DEVICE_ATTR(name, 0644, mtd_##name##_show, mtd_##name##_store)
134b4e24863SZhen Lei 
mtd_type_show(struct device * dev,struct device_attribute * attr,char * buf)1351f24b5a8SDavid Brownell static ssize_t mtd_type_show(struct device *dev,
1361f24b5a8SDavid Brownell 		struct device_attribute *attr, char *buf)
1371f24b5a8SDavid Brownell {
138d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
1391f24b5a8SDavid Brownell 	char *type;
1401f24b5a8SDavid Brownell 
1411f24b5a8SDavid Brownell 	switch (mtd->type) {
1421f24b5a8SDavid Brownell 	case MTD_ABSENT:
1431f24b5a8SDavid Brownell 		type = "absent";
1441f24b5a8SDavid Brownell 		break;
1451f24b5a8SDavid Brownell 	case MTD_RAM:
1461f24b5a8SDavid Brownell 		type = "ram";
1471f24b5a8SDavid Brownell 		break;
1481f24b5a8SDavid Brownell 	case MTD_ROM:
1491f24b5a8SDavid Brownell 		type = "rom";
1501f24b5a8SDavid Brownell 		break;
1511f24b5a8SDavid Brownell 	case MTD_NORFLASH:
1521f24b5a8SDavid Brownell 		type = "nor";
1531f24b5a8SDavid Brownell 		break;
1541f24b5a8SDavid Brownell 	case MTD_NANDFLASH:
1551f24b5a8SDavid Brownell 		type = "nand";
1561f24b5a8SDavid Brownell 		break;
1571f24b5a8SDavid Brownell 	case MTD_DATAFLASH:
1581f24b5a8SDavid Brownell 		type = "dataflash";
1591f24b5a8SDavid Brownell 		break;
1601f24b5a8SDavid Brownell 	case MTD_UBIVOLUME:
1611f24b5a8SDavid Brownell 		type = "ubi";
1621f24b5a8SDavid Brownell 		break;
163f4837246SHuang Shijie 	case MTD_MLCNANDFLASH:
164f4837246SHuang Shijie 		type = "mlc-nand";
165f4837246SHuang Shijie 		break;
1661f24b5a8SDavid Brownell 	default:
1671f24b5a8SDavid Brownell 		type = "unknown";
1681f24b5a8SDavid Brownell 	}
1691f24b5a8SDavid Brownell 
1705b2fbe0cSTian Tao 	return sysfs_emit(buf, "%s\n", type);
1711f24b5a8SDavid Brownell }
172a17da115SZhen Lei MTD_DEVICE_ATTR_RO(type);
173694bb7fcSKevin Cernekee 
mtd_flags_show(struct device * dev,struct device_attribute * attr,char * buf)174694bb7fcSKevin Cernekee static ssize_t mtd_flags_show(struct device *dev,
175694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
176694bb7fcSKevin Cernekee {
177d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
178694bb7fcSKevin Cernekee 
1795b2fbe0cSTian Tao 	return sysfs_emit(buf, "0x%lx\n", (unsigned long)mtd->flags);
180694bb7fcSKevin Cernekee }
181a17da115SZhen Lei MTD_DEVICE_ATTR_RO(flags);
182694bb7fcSKevin Cernekee 
mtd_size_show(struct device * dev,struct device_attribute * attr,char * buf)183694bb7fcSKevin Cernekee static ssize_t mtd_size_show(struct device *dev,
184694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
185694bb7fcSKevin Cernekee {
186d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
187694bb7fcSKevin Cernekee 
1885b2fbe0cSTian Tao 	return sysfs_emit(buf, "%llu\n", (unsigned long long)mtd->size);
189694bb7fcSKevin Cernekee }
190a17da115SZhen Lei MTD_DEVICE_ATTR_RO(size);
191694bb7fcSKevin Cernekee 
mtd_erasesize_show(struct device * dev,struct device_attribute * attr,char * buf)192694bb7fcSKevin Cernekee static ssize_t mtd_erasesize_show(struct device *dev,
193694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
194694bb7fcSKevin Cernekee {
195d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
196694bb7fcSKevin Cernekee 
1975b2fbe0cSTian Tao 	return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize);
198694bb7fcSKevin Cernekee }
199a17da115SZhen Lei MTD_DEVICE_ATTR_RO(erasesize);
200694bb7fcSKevin Cernekee 
mtd_writesize_show(struct device * dev,struct device_attribute * attr,char * buf)201694bb7fcSKevin Cernekee static ssize_t mtd_writesize_show(struct device *dev,
202694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
203694bb7fcSKevin Cernekee {
204d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
205694bb7fcSKevin Cernekee 
2065b2fbe0cSTian Tao 	return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->writesize);
207694bb7fcSKevin Cernekee }
208a17da115SZhen Lei MTD_DEVICE_ATTR_RO(writesize);
209694bb7fcSKevin Cernekee 
mtd_subpagesize_show(struct device * dev,struct device_attribute * attr,char * buf)210e7693548SArtem Bityutskiy static ssize_t mtd_subpagesize_show(struct device *dev,
211e7693548SArtem Bityutskiy 		struct device_attribute *attr, char *buf)
212e7693548SArtem Bityutskiy {
213d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
214e7693548SArtem Bityutskiy 	unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
215e7693548SArtem Bityutskiy 
2165b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", subpagesize);
217e7693548SArtem Bityutskiy }
218a17da115SZhen Lei MTD_DEVICE_ATTR_RO(subpagesize);
219e7693548SArtem Bityutskiy 
mtd_oobsize_show(struct device * dev,struct device_attribute * attr,char * buf)220694bb7fcSKevin Cernekee static ssize_t mtd_oobsize_show(struct device *dev,
221694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
222694bb7fcSKevin Cernekee {
223d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
224694bb7fcSKevin Cernekee 
2255b2fbe0cSTian Tao 	return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->oobsize);
226694bb7fcSKevin Cernekee }
227a17da115SZhen Lei MTD_DEVICE_ATTR_RO(oobsize);
228694bb7fcSKevin Cernekee 
mtd_oobavail_show(struct device * dev,struct device_attribute * attr,char * buf)2297cc9aa66SXiaolei Li static ssize_t mtd_oobavail_show(struct device *dev,
2307cc9aa66SXiaolei Li 				 struct device_attribute *attr, char *buf)
2317cc9aa66SXiaolei Li {
2327cc9aa66SXiaolei Li 	struct mtd_info *mtd = dev_get_drvdata(dev);
2337cc9aa66SXiaolei Li 
2345b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", mtd->oobavail);
2357cc9aa66SXiaolei Li }
236a17da115SZhen Lei MTD_DEVICE_ATTR_RO(oobavail);
2377cc9aa66SXiaolei Li 
mtd_numeraseregions_show(struct device * dev,struct device_attribute * attr,char * buf)238694bb7fcSKevin Cernekee static ssize_t mtd_numeraseregions_show(struct device *dev,
239694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
240694bb7fcSKevin Cernekee {
241d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
242694bb7fcSKevin Cernekee 
2435b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", mtd->numeraseregions);
244694bb7fcSKevin Cernekee }
245a17da115SZhen Lei MTD_DEVICE_ATTR_RO(numeraseregions);
246694bb7fcSKevin Cernekee 
mtd_name_show(struct device * dev,struct device_attribute * attr,char * buf)247694bb7fcSKevin Cernekee static ssize_t mtd_name_show(struct device *dev,
248694bb7fcSKevin Cernekee 		struct device_attribute *attr, char *buf)
249694bb7fcSKevin Cernekee {
250d5de20a9SArtem Bityutskiy 	struct mtd_info *mtd = dev_get_drvdata(dev);
251694bb7fcSKevin Cernekee 
2525b2fbe0cSTian Tao 	return sysfs_emit(buf, "%s\n", mtd->name);
253694bb7fcSKevin Cernekee }
254a17da115SZhen Lei MTD_DEVICE_ATTR_RO(name);
2551f24b5a8SDavid Brownell 
mtd_ecc_strength_show(struct device * dev,struct device_attribute * attr,char * buf)256a9b672e8SMike Dunn static ssize_t mtd_ecc_strength_show(struct device *dev,
257a9b672e8SMike Dunn 				     struct device_attribute *attr, char *buf)
258a9b672e8SMike Dunn {
259a9b672e8SMike Dunn 	struct mtd_info *mtd = dev_get_drvdata(dev);
260a9b672e8SMike Dunn 
2615b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", mtd->ecc_strength);
262a9b672e8SMike Dunn }
263a17da115SZhen Lei MTD_DEVICE_ATTR_RO(ecc_strength);
264a9b672e8SMike Dunn 
mtd_bitflip_threshold_show(struct device * dev,struct device_attribute * attr,char * buf)265d062d4edSMike Dunn static ssize_t mtd_bitflip_threshold_show(struct device *dev,
266d062d4edSMike Dunn 					  struct device_attribute *attr,
267d062d4edSMike Dunn 					  char *buf)
268d062d4edSMike Dunn {
269d062d4edSMike Dunn 	struct mtd_info *mtd = dev_get_drvdata(dev);
270d062d4edSMike Dunn 
2715b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", mtd->bitflip_threshold);
272d062d4edSMike Dunn }
273d062d4edSMike Dunn 
mtd_bitflip_threshold_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)274d062d4edSMike Dunn static ssize_t mtd_bitflip_threshold_store(struct device *dev,
275d062d4edSMike Dunn 					   struct device_attribute *attr,
276d062d4edSMike Dunn 					   const char *buf, size_t count)
277d062d4edSMike Dunn {
278d062d4edSMike Dunn 	struct mtd_info *mtd = dev_get_drvdata(dev);
279d062d4edSMike Dunn 	unsigned int bitflip_threshold;
280d062d4edSMike Dunn 	int retval;
281d062d4edSMike Dunn 
282d062d4edSMike Dunn 	retval = kstrtouint(buf, 0, &bitflip_threshold);
283d062d4edSMike Dunn 	if (retval)
284d062d4edSMike Dunn 		return retval;
285d062d4edSMike Dunn 
286d062d4edSMike Dunn 	mtd->bitflip_threshold = bitflip_threshold;
287d062d4edSMike Dunn 	return count;
288d062d4edSMike Dunn }
289a17da115SZhen Lei MTD_DEVICE_ATTR_RW(bitflip_threshold);
290d062d4edSMike Dunn 
mtd_ecc_step_size_show(struct device * dev,struct device_attribute * attr,char * buf)291bf977e3fSHuang Shijie static ssize_t mtd_ecc_step_size_show(struct device *dev,
292bf977e3fSHuang Shijie 		struct device_attribute *attr, char *buf)
293bf977e3fSHuang Shijie {
294bf977e3fSHuang Shijie 	struct mtd_info *mtd = dev_get_drvdata(dev);
295bf977e3fSHuang Shijie 
2965b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", mtd->ecc_step_size);
297bf977e3fSHuang Shijie 
298bf977e3fSHuang Shijie }
299a17da115SZhen Lei MTD_DEVICE_ATTR_RO(ecc_step_size);
300bf977e3fSHuang Shijie 
mtd_corrected_bits_show(struct device * dev,struct device_attribute * attr,char * buf)301a17da115SZhen Lei static ssize_t mtd_corrected_bits_show(struct device *dev,
302990a3af0SEzequiel Garcia 		struct device_attribute *attr, char *buf)
303990a3af0SEzequiel Garcia {
304990a3af0SEzequiel Garcia 	struct mtd_info *mtd = dev_get_drvdata(dev);
305990a3af0SEzequiel Garcia 	struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
306990a3af0SEzequiel Garcia 
3075b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", ecc_stats->corrected);
308990a3af0SEzequiel Garcia }
309a17da115SZhen Lei MTD_DEVICE_ATTR_RO(corrected_bits);	/* ecc stats corrected */
310990a3af0SEzequiel Garcia 
mtd_ecc_failures_show(struct device * dev,struct device_attribute * attr,char * buf)311a17da115SZhen Lei static ssize_t mtd_ecc_failures_show(struct device *dev,
312990a3af0SEzequiel Garcia 		struct device_attribute *attr, char *buf)
313990a3af0SEzequiel Garcia {
314990a3af0SEzequiel Garcia 	struct mtd_info *mtd = dev_get_drvdata(dev);
315990a3af0SEzequiel Garcia 	struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
316990a3af0SEzequiel Garcia 
3175b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", ecc_stats->failed);
318990a3af0SEzequiel Garcia }
319a17da115SZhen Lei MTD_DEVICE_ATTR_RO(ecc_failures);	/* ecc stats errors */
320990a3af0SEzequiel Garcia 
mtd_bad_blocks_show(struct device * dev,struct device_attribute * attr,char * buf)321a17da115SZhen Lei static ssize_t mtd_bad_blocks_show(struct device *dev,
322990a3af0SEzequiel Garcia 		struct device_attribute *attr, char *buf)
323990a3af0SEzequiel Garcia {
324990a3af0SEzequiel Garcia 	struct mtd_info *mtd = dev_get_drvdata(dev);
325990a3af0SEzequiel Garcia 	struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
326990a3af0SEzequiel Garcia 
3275b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", ecc_stats->badblocks);
328990a3af0SEzequiel Garcia }
329a17da115SZhen Lei MTD_DEVICE_ATTR_RO(bad_blocks);
330990a3af0SEzequiel Garcia 
mtd_bbt_blocks_show(struct device * dev,struct device_attribute * attr,char * buf)331a17da115SZhen Lei static ssize_t mtd_bbt_blocks_show(struct device *dev,
332990a3af0SEzequiel Garcia 		struct device_attribute *attr, char *buf)
333990a3af0SEzequiel Garcia {
334990a3af0SEzequiel Garcia 	struct mtd_info *mtd = dev_get_drvdata(dev);
335990a3af0SEzequiel Garcia 	struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
336990a3af0SEzequiel Garcia 
3375b2fbe0cSTian Tao 	return sysfs_emit(buf, "%u\n", ecc_stats->bbtblocks);
338990a3af0SEzequiel Garcia }
339a17da115SZhen Lei MTD_DEVICE_ATTR_RO(bbt_blocks);
340990a3af0SEzequiel Garcia 
3411f24b5a8SDavid Brownell static struct attribute *mtd_attrs[] = {
342694bb7fcSKevin Cernekee 	&dev_attr_type.attr,
343694bb7fcSKevin Cernekee 	&dev_attr_flags.attr,
344694bb7fcSKevin Cernekee 	&dev_attr_size.attr,
345694bb7fcSKevin Cernekee 	&dev_attr_erasesize.attr,
346694bb7fcSKevin Cernekee 	&dev_attr_writesize.attr,
347e7693548SArtem Bityutskiy 	&dev_attr_subpagesize.attr,
348694bb7fcSKevin Cernekee 	&dev_attr_oobsize.attr,
3497cc9aa66SXiaolei Li 	&dev_attr_oobavail.attr,
350694bb7fcSKevin Cernekee 	&dev_attr_numeraseregions.attr,
351694bb7fcSKevin Cernekee 	&dev_attr_name.attr,
352a9b672e8SMike Dunn 	&dev_attr_ecc_strength.attr,
353bf977e3fSHuang Shijie 	&dev_attr_ecc_step_size.attr,
354990a3af0SEzequiel Garcia 	&dev_attr_corrected_bits.attr,
355990a3af0SEzequiel Garcia 	&dev_attr_ecc_failures.attr,
356990a3af0SEzequiel Garcia 	&dev_attr_bad_blocks.attr,
357990a3af0SEzequiel Garcia 	&dev_attr_bbt_blocks.attr,
358d062d4edSMike Dunn 	&dev_attr_bitflip_threshold.attr,
3591f24b5a8SDavid Brownell 	NULL,
3601f24b5a8SDavid Brownell };
36154c738f6SAxel Lin ATTRIBUTE_GROUPS(mtd);
3621f24b5a8SDavid Brownell 
36375864b30SBhumika Goyal static const struct device_type mtd_devtype = {
3641f24b5a8SDavid Brownell 	.name		= "mtd",
3651f24b5a8SDavid Brownell 	.groups		= mtd_groups,
3661f24b5a8SDavid Brownell 	.release	= mtd_release,
3671f24b5a8SDavid Brownell };
3681f24b5a8SDavid Brownell 
369ad5e35f5SMiquel Raynal static bool mtd_expert_analysis_mode;
370ad5e35f5SMiquel Raynal 
371ad5e35f5SMiquel Raynal #ifdef CONFIG_DEBUG_FS
mtd_check_expert_analysis_mode(void)372ad5e35f5SMiquel Raynal bool mtd_check_expert_analysis_mode(void)
3731018c94bSZhuohao Lee {
374ad5e35f5SMiquel Raynal 	const char *mtd_expert_analysis_warning =
375ad5e35f5SMiquel Raynal 		"Bad block checks have been entirely disabled.\n"
376ad5e35f5SMiquel Raynal 		"This is only reserved for post-mortem forensics and debug purposes.\n"
377ad5e35f5SMiquel Raynal 		"Never enable this mode if you do not know what you are doing!\n";
3781018c94bSZhuohao Lee 
379ad5e35f5SMiquel Raynal 	return WARN_ONCE(mtd_expert_analysis_mode, mtd_expert_analysis_warning);
3801018c94bSZhuohao Lee }
381ad5e35f5SMiquel Raynal EXPORT_SYMBOL_GPL(mtd_check_expert_analysis_mode);
382ad5e35f5SMiquel Raynal #endif
3831018c94bSZhuohao Lee 
3841018c94bSZhuohao Lee static struct dentry *dfs_dir_mtd;
3851018c94bSZhuohao Lee 
mtd_debugfs_populate(struct mtd_info * mtd)3861018c94bSZhuohao Lee static void mtd_debugfs_populate(struct mtd_info *mtd)
3871018c94bSZhuohao Lee {
3881018c94bSZhuohao Lee 	struct device *dev = &mtd->dev;
3891018c94bSZhuohao Lee 
3901018c94bSZhuohao Lee 	if (IS_ERR_OR_NULL(dfs_dir_mtd))
3911018c94bSZhuohao Lee 		return;
3921018c94bSZhuohao Lee 
393ec090a03STudor Ambarus 	mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(dev), dfs_dir_mtd);
3941018c94bSZhuohao Lee }
3951018c94bSZhuohao Lee 
396b4caecd4SChristoph Hellwig #ifndef CONFIG_MMU
mtd_mmap_capabilities(struct mtd_info * mtd)397b4caecd4SChristoph Hellwig unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
398b4caecd4SChristoph Hellwig {
399b4caecd4SChristoph Hellwig 	switch (mtd->type) {
400b4caecd4SChristoph Hellwig 	case MTD_RAM:
401b4caecd4SChristoph Hellwig 		return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC |
402b4caecd4SChristoph Hellwig 			NOMMU_MAP_READ | NOMMU_MAP_WRITE;
403b4caecd4SChristoph Hellwig 	case MTD_ROM:
404b4caecd4SChristoph Hellwig 		return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC |
405b4caecd4SChristoph Hellwig 			NOMMU_MAP_READ;
406b4caecd4SChristoph Hellwig 	default:
407b4caecd4SChristoph Hellwig 		return NOMMU_MAP_COPY;
408b4caecd4SChristoph Hellwig 	}
409b4caecd4SChristoph Hellwig }
410706a4e5aSArnd Bergmann EXPORT_SYMBOL_GPL(mtd_mmap_capabilities);
411b4caecd4SChristoph Hellwig #endif
412b4caecd4SChristoph Hellwig 
mtd_reboot_notifier(struct notifier_block * n,unsigned long state,void * cmd)4133efe41beSBrian Norris static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
4143efe41beSBrian Norris 			       void *cmd)
4153efe41beSBrian Norris {
4163efe41beSBrian Norris 	struct mtd_info *mtd;
4173efe41beSBrian Norris 
4183efe41beSBrian Norris 	mtd = container_of(n, struct mtd_info, reboot_notifier);
4193efe41beSBrian Norris 	mtd->_reboot(mtd);
4203efe41beSBrian Norris 
4213efe41beSBrian Norris 	return NOTIFY_DONE;
4223efe41beSBrian Norris }
4233efe41beSBrian Norris 
4241da177e4SLinus Torvalds /**
425477b0229SBoris Brezillon  * mtd_wunit_to_pairing_info - get pairing information of a wunit
426477b0229SBoris Brezillon  * @mtd: pointer to new MTD device info structure
427477b0229SBoris Brezillon  * @wunit: write unit we are interested in
428477b0229SBoris Brezillon  * @info: returned pairing information
429477b0229SBoris Brezillon  *
430477b0229SBoris Brezillon  * Retrieve pairing information associated to the wunit.
431477b0229SBoris Brezillon  * This is mainly useful when dealing with MLC/TLC NANDs where pages can be
432477b0229SBoris Brezillon  * paired together, and where programming a page may influence the page it is
433477b0229SBoris Brezillon  * paired with.
434477b0229SBoris Brezillon  * The notion of page is replaced by the term wunit (write-unit) to stay
435477b0229SBoris Brezillon  * consistent with the ->writesize field.
436477b0229SBoris Brezillon  *
437477b0229SBoris Brezillon  * The @wunit argument can be extracted from an absolute offset using
438477b0229SBoris Brezillon  * mtd_offset_to_wunit(). @info is filled with the pairing information attached
439477b0229SBoris Brezillon  * to @wunit.
440477b0229SBoris Brezillon  *
441477b0229SBoris Brezillon  * From the pairing info the MTD user can find all the wunits paired with
442477b0229SBoris Brezillon  * @wunit using the following loop:
443477b0229SBoris Brezillon  *
444477b0229SBoris Brezillon  * for (i = 0; i < mtd_pairing_groups(mtd); i++) {
445477b0229SBoris Brezillon  *	info.pair = i;
446477b0229SBoris Brezillon  *	mtd_pairing_info_to_wunit(mtd, &info);
447477b0229SBoris Brezillon  *	...
448477b0229SBoris Brezillon  * }
449477b0229SBoris Brezillon  */
mtd_wunit_to_pairing_info(struct mtd_info * mtd,int wunit,struct mtd_pairing_info * info)450477b0229SBoris Brezillon int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
451477b0229SBoris Brezillon 			      struct mtd_pairing_info *info)
452477b0229SBoris Brezillon {
45346b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
45446b5889cSMiquel Raynal 	int npairs = mtd_wunit_per_eb(master) / mtd_pairing_groups(master);
455477b0229SBoris Brezillon 
456477b0229SBoris Brezillon 	if (wunit < 0 || wunit >= npairs)
457477b0229SBoris Brezillon 		return -EINVAL;
458477b0229SBoris Brezillon 
45946b5889cSMiquel Raynal 	if (master->pairing && master->pairing->get_info)
46046b5889cSMiquel Raynal 		return master->pairing->get_info(master, wunit, info);
461477b0229SBoris Brezillon 
462477b0229SBoris Brezillon 	info->group = 0;
463477b0229SBoris Brezillon 	info->pair = wunit;
464477b0229SBoris Brezillon 
465477b0229SBoris Brezillon 	return 0;
466477b0229SBoris Brezillon }
467477b0229SBoris Brezillon EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info);
468477b0229SBoris Brezillon 
469477b0229SBoris Brezillon /**
470c77a9312SXiaolei Li  * mtd_pairing_info_to_wunit - get wunit from pairing information
471477b0229SBoris Brezillon  * @mtd: pointer to new MTD device info structure
472477b0229SBoris Brezillon  * @info: pairing information struct
473477b0229SBoris Brezillon  *
474477b0229SBoris Brezillon  * Returns a positive number representing the wunit associated to the info
475477b0229SBoris Brezillon  * struct, or a negative error code.
476477b0229SBoris Brezillon  *
477477b0229SBoris Brezillon  * This is the reverse of mtd_wunit_to_pairing_info(), and can help one to
478477b0229SBoris Brezillon  * iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info()
479477b0229SBoris Brezillon  * doc).
480477b0229SBoris Brezillon  *
481477b0229SBoris Brezillon  * It can also be used to only program the first page of each pair (i.e.
482477b0229SBoris Brezillon  * page attached to group 0), which allows one to use an MLC NAND in
483477b0229SBoris Brezillon  * software-emulated SLC mode:
484477b0229SBoris Brezillon  *
485477b0229SBoris Brezillon  * info.group = 0;
486477b0229SBoris Brezillon  * npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
487477b0229SBoris Brezillon  * for (info.pair = 0; info.pair < npairs; info.pair++) {
488477b0229SBoris Brezillon  *	wunit = mtd_pairing_info_to_wunit(mtd, &info);
489477b0229SBoris Brezillon  *	mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit),
490477b0229SBoris Brezillon  *		  mtd->writesize, &retlen, buf + (i * mtd->writesize));
491477b0229SBoris Brezillon  * }
492477b0229SBoris Brezillon  */
mtd_pairing_info_to_wunit(struct mtd_info * mtd,const struct mtd_pairing_info * info)493477b0229SBoris Brezillon int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
494477b0229SBoris Brezillon 			      const struct mtd_pairing_info *info)
495477b0229SBoris Brezillon {
49646b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
49746b5889cSMiquel Raynal 	int ngroups = mtd_pairing_groups(master);
49846b5889cSMiquel Raynal 	int npairs = mtd_wunit_per_eb(master) / ngroups;
499477b0229SBoris Brezillon 
500477b0229SBoris Brezillon 	if (!info || info->pair < 0 || info->pair >= npairs ||
501477b0229SBoris Brezillon 	    info->group < 0 || info->group >= ngroups)
502477b0229SBoris Brezillon 		return -EINVAL;
503477b0229SBoris Brezillon 
50446b5889cSMiquel Raynal 	if (master->pairing && master->pairing->get_wunit)
50546b5889cSMiquel Raynal 		return mtd->pairing->get_wunit(master, info);
506477b0229SBoris Brezillon 
507477b0229SBoris Brezillon 	return info->pair;
508477b0229SBoris Brezillon }
509477b0229SBoris Brezillon EXPORT_SYMBOL_GPL(mtd_pairing_info_to_wunit);
510477b0229SBoris Brezillon 
511477b0229SBoris Brezillon /**
512477b0229SBoris Brezillon  * mtd_pairing_groups - get the number of pairing groups
513477b0229SBoris Brezillon  * @mtd: pointer to new MTD device info structure
514477b0229SBoris Brezillon  *
515477b0229SBoris Brezillon  * Returns the number of pairing groups.
516477b0229SBoris Brezillon  *
517477b0229SBoris Brezillon  * This number is usually equal to the number of bits exposed by a single
518477b0229SBoris Brezillon  * cell, and can be used in conjunction with mtd_pairing_info_to_wunit()
519477b0229SBoris Brezillon  * to iterate over all pages of a given pair.
520477b0229SBoris Brezillon  */
mtd_pairing_groups(struct mtd_info * mtd)521477b0229SBoris Brezillon int mtd_pairing_groups(struct mtd_info *mtd)
522477b0229SBoris Brezillon {
52346b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
52446b5889cSMiquel Raynal 
52546b5889cSMiquel Raynal 	if (!master->pairing || !master->pairing->ngroups)
526477b0229SBoris Brezillon 		return 1;
527477b0229SBoris Brezillon 
52846b5889cSMiquel Raynal 	return master->pairing->ngroups;
529477b0229SBoris Brezillon }
530477b0229SBoris Brezillon EXPORT_SYMBOL_GPL(mtd_pairing_groups);
531477b0229SBoris Brezillon 
mtd_nvmem_reg_read(void * priv,unsigned int offset,void * val,size_t bytes)532c4dfa25aSAlban Bedel static int mtd_nvmem_reg_read(void *priv, unsigned int offset,
533c4dfa25aSAlban Bedel 			      void *val, size_t bytes)
534c4dfa25aSAlban Bedel {
535c4dfa25aSAlban Bedel 	struct mtd_info *mtd = priv;
536c4dfa25aSAlban Bedel 	size_t retlen;
537c4dfa25aSAlban Bedel 	int err;
538c4dfa25aSAlban Bedel 
539c4dfa25aSAlban Bedel 	err = mtd_read(mtd, offset, bytes, &retlen, val);
540c4dfa25aSAlban Bedel 	if (err && err != -EUCLEAN)
541c4dfa25aSAlban Bedel 		return err;
542c4dfa25aSAlban Bedel 
543c4dfa25aSAlban Bedel 	return retlen == bytes ? 0 : -EIO;
544c4dfa25aSAlban Bedel }
545c4dfa25aSAlban Bedel 
mtd_nvmem_add(struct mtd_info * mtd)546c4dfa25aSAlban Bedel static int mtd_nvmem_add(struct mtd_info *mtd)
547c4dfa25aSAlban Bedel {
548658c4448SAnsuel Smith 	struct device_node *node = mtd_get_of_node(mtd);
549c4dfa25aSAlban Bedel 	struct nvmem_config config = {};
550c4dfa25aSAlban Bedel 
55175f32f4bSMiquel Raynal 	config.id = NVMEM_DEVID_NONE;
552c4dfa25aSAlban Bedel 	config.dev = &mtd->dev;
5537b01b723SRicardo Ribalda Delgado 	config.name = dev_name(&mtd->dev);
554c4dfa25aSAlban Bedel 	config.owner = THIS_MODULE;
55526e2fe4cSRafał Miłecki 	config.add_legacy_fixed_of_cells = of_device_is_compatible(node, "nvmem-cells");
556c4dfa25aSAlban Bedel 	config.reg_read = mtd_nvmem_reg_read;
557c4dfa25aSAlban Bedel 	config.size = mtd->size;
558c4dfa25aSAlban Bedel 	config.word_size = 1;
559c4dfa25aSAlban Bedel 	config.stride = 1;
560c4dfa25aSAlban Bedel 	config.read_only = true;
561c4dfa25aSAlban Bedel 	config.root_only = true;
5626c762189SChristophe Kerello 	config.ignore_wp = true;
563658c4448SAnsuel Smith 	config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
564c4dfa25aSAlban Bedel 	config.priv = mtd;
565c4dfa25aSAlban Bedel 
566c4dfa25aSAlban Bedel 	mtd->nvmem = nvmem_register(&config);
567c4dfa25aSAlban Bedel 	if (IS_ERR(mtd->nvmem)) {
568c4dfa25aSAlban Bedel 		/* Just ignore if there is no NVMEM support in the kernel */
5695cab0615SMiquel Raynal 		if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP)
570c4dfa25aSAlban Bedel 			mtd->nvmem = NULL;
5715cab0615SMiquel Raynal 		else
5725cab0615SMiquel Raynal 			return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem),
5735cab0615SMiquel Raynal 					     "Failed to register NVMEM device\n");
574c4dfa25aSAlban Bedel 	}
575c4dfa25aSAlban Bedel 
576c4dfa25aSAlban Bedel 	return 0;
577c4dfa25aSAlban Bedel }
578c4dfa25aSAlban Bedel 
mtd_check_of_node(struct mtd_info * mtd)579ad9b10d1SChristian Marangi static void mtd_check_of_node(struct mtd_info *mtd)
580ad9b10d1SChristian Marangi {
581ad9b10d1SChristian Marangi 	struct device_node *partitions, *parent_dn, *mtd_dn = NULL;
582ad9b10d1SChristian Marangi 	const char *pname, *prefix = "partition-";
583ad9b10d1SChristian Marangi 	int plen, mtd_name_len, offset, prefix_len;
584ad9b10d1SChristian Marangi 
585ad9b10d1SChristian Marangi 	/* Check if MTD already has a device node */
586c5f5d0cdSRafał Miłecki 	if (mtd_get_of_node(mtd))
587ad9b10d1SChristian Marangi 		return;
588ad9b10d1SChristian Marangi 
5897ec4cdb3STetsuo Handa 	if (!mtd_is_partition(mtd))
5907ec4cdb3STetsuo Handa 		return;
591c5f5d0cdSRafał Miłecki 
592c5f5d0cdSRafał Miłecki 	parent_dn = of_node_get(mtd_get_of_node(mtd->parent));
593ad9b10d1SChristian Marangi 	if (!parent_dn)
594ad9b10d1SChristian Marangi 		return;
595ad9b10d1SChristian Marangi 
5962df11f00SRafał Miłecki 	if (mtd_is_partition(mtd->parent))
5972df11f00SRafał Miłecki 		partitions = of_node_get(parent_dn);
5982df11f00SRafał Miłecki 	else
599ad9b10d1SChristian Marangi 		partitions = of_get_child_by_name(parent_dn, "partitions");
600ad9b10d1SChristian Marangi 	if (!partitions)
601ad9b10d1SChristian Marangi 		goto exit_parent;
602ad9b10d1SChristian Marangi 
603ad9b10d1SChristian Marangi 	prefix_len = strlen(prefix);
604ad9b10d1SChristian Marangi 	mtd_name_len = strlen(mtd->name);
605ad9b10d1SChristian Marangi 
606ad9b10d1SChristian Marangi 	/* Search if a partition is defined with the same name */
607ad9b10d1SChristian Marangi 	for_each_child_of_node(partitions, mtd_dn) {
608ad9b10d1SChristian Marangi 		/* Skip partition with no/wrong prefix */
609c5f5d0cdSRafał Miłecki 		if (!of_node_name_prefix(mtd_dn, prefix))
610ad9b10d1SChristian Marangi 			continue;
611ad9b10d1SChristian Marangi 
612ad9b10d1SChristian Marangi 		/* Label have priority. Check that first */
613c5f5d0cdSRafał Miłecki 		if (!of_property_read_string(mtd_dn, "label", &pname)) {
614c5f5d0cdSRafał Miłecki 			offset = 0;
615c5f5d0cdSRafał Miłecki 		} else {
616c5f5d0cdSRafał Miłecki 			pname = mtd_dn->name;
617ad9b10d1SChristian Marangi 			offset = prefix_len;
618ad9b10d1SChristian Marangi 		}
619ad9b10d1SChristian Marangi 
620ad9b10d1SChristian Marangi 		plen = strlen(pname) - offset;
621ad9b10d1SChristian Marangi 		if (plen == mtd_name_len &&
622ad9b10d1SChristian Marangi 		    !strncmp(mtd->name, pname + offset, plen)) {
6232df11f00SRafał Miłecki 			mtd_set_of_node(mtd, mtd_dn);
624ad9b10d1SChristian Marangi 			break;
625ad9b10d1SChristian Marangi 		}
626ad9b10d1SChristian Marangi 	}
627ad9b10d1SChristian Marangi 
628ad9b10d1SChristian Marangi 	of_node_put(partitions);
629ad9b10d1SChristian Marangi exit_parent:
630ad9b10d1SChristian Marangi 	of_node_put(parent_dn);
631ad9b10d1SChristian Marangi }
632ad9b10d1SChristian Marangi 
633477b0229SBoris Brezillon /**
6341da177e4SLinus Torvalds  *	add_mtd_device - register an MTD device
6351da177e4SLinus Torvalds  *	@mtd: pointer to new MTD device info structure
6361da177e4SLinus Torvalds  *
6371da177e4SLinus Torvalds  *	Add a device to the list of MTD devices present in the system, and
6381da177e4SLinus Torvalds  *	notify each currently active MTD 'user' of its arrival. Returns
63957dd990cSBrian Norris  *	zero on success or non-zero on failure.
6401da177e4SLinus Torvalds  */
6411da177e4SLinus Torvalds 
add_mtd_device(struct mtd_info * mtd)6421da177e4SLinus Torvalds int add_mtd_device(struct mtd_info *mtd)
6431da177e4SLinus Torvalds {
64482e214f6SVincent Whitchurch 	struct device_node *np = mtd_get_of_node(mtd);
64546b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
646b520e412SBen Hutchings 	struct mtd_notifier *not;
64782e214f6SVincent Whitchurch 	int i, error, ofidx;
6481da177e4SLinus Torvalds 
649be0dbff8SBrian Norris 	/*
650be0dbff8SBrian Norris 	 * May occur, for instance, on buggy drivers which call
651be0dbff8SBrian Norris 	 * mtd_device_parse_register() multiple times on the same master MTD,
652be0dbff8SBrian Norris 	 * especially with CONFIG_MTD_PARTITIONED_MASTER=y.
653be0dbff8SBrian Norris 	 */
654fa06052dSJan Kara 	if (WARN_ONCE(mtd->dev.type, "MTD already registered\n"))
655be0dbff8SBrian Norris 		return -EEXIST;
656be0dbff8SBrian Norris 
657783ed81fSArtem B. Bityutskiy 	BUG_ON(mtd->writesize == 0);
65833f45c44SBoris Brezillon 
6592431c4f5SBoris Brezillon 	/*
6602431c4f5SBoris Brezillon 	 * MTD drivers should implement ->_{write,read}() or
6612431c4f5SBoris Brezillon 	 * ->_{write,read}_oob(), but not both.
6622431c4f5SBoris Brezillon 	 */
6632431c4f5SBoris Brezillon 	if (WARN_ON((mtd->_write && mtd->_write_oob) ||
6642431c4f5SBoris Brezillon 		    (mtd->_read && mtd->_read_oob)))
6652431c4f5SBoris Brezillon 		return -EINVAL;
6662431c4f5SBoris Brezillon 
66746b5889cSMiquel Raynal 	if (WARN_ON((!mtd->erasesize || !master->_erase) &&
66833f45c44SBoris Brezillon 		    !(mtd->flags & MTD_NO_ERASE)))
66933f45c44SBoris Brezillon 		return -EINVAL;
67033f45c44SBoris Brezillon 
6719e3307a1SBoris Brezillon 	/*
6729e3307a1SBoris Brezillon 	 * MTD_SLC_ON_MLC_EMULATION can only be set on partitions, when the
6739e3307a1SBoris Brezillon 	 * master is an MLC NAND and has a proper pairing scheme defined.
6749e3307a1SBoris Brezillon 	 * We also reject masters that implement ->_writev() for now, because
6759e3307a1SBoris Brezillon 	 * NAND controller drivers don't implement this hook, and adding the
6769e3307a1SBoris Brezillon 	 * SLC -> MLC address/length conversion to this path is useless if we
6779e3307a1SBoris Brezillon 	 * don't have a user.
6789e3307a1SBoris Brezillon 	 */
6799e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION &&
6809e3307a1SBoris Brezillon 	    (!mtd_is_partition(mtd) || master->type != MTD_MLCNANDFLASH ||
6819e3307a1SBoris Brezillon 	     !master->pairing || master->_writev))
6829e3307a1SBoris Brezillon 		return -EINVAL;
6839e3307a1SBoris Brezillon 
68448b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
6851da177e4SLinus Torvalds 
68682e214f6SVincent Whitchurch 	ofidx = -1;
68782e214f6SVincent Whitchurch 	if (np)
68882e214f6SVincent Whitchurch 		ofidx = of_alias_get_id(np, "mtd");
68982e214f6SVincent Whitchurch 	if (ofidx >= 0)
69082e214f6SVincent Whitchurch 		i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL);
69182e214f6SVincent Whitchurch 	else
692589e9c4dSTejun Heo 		i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
69357dd990cSBrian Norris 	if (i < 0) {
69457dd990cSBrian Norris 		error = i;
695b520e412SBen Hutchings 		goto fail_locked;
69657dd990cSBrian Norris 	}
697b520e412SBen Hutchings 
6981da177e4SLinus Torvalds 	mtd->index = i;
69919bfa9ebSTomas Winkler 	kref_init(&mtd->refcnt);
7001da177e4SLinus Torvalds 
701d062d4edSMike Dunn 	/* default value if not set by driver */
702d062d4edSMike Dunn 	if (mtd->bitflip_threshold == 0)
703d062d4edSMike Dunn 		mtd->bitflip_threshold = mtd->ecc_strength;
704d062d4edSMike Dunn 
7059e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
7069e3307a1SBoris Brezillon 		int ngroups = mtd_pairing_groups(master);
7079e3307a1SBoris Brezillon 
7089e3307a1SBoris Brezillon 		mtd->erasesize /= ngroups;
7099e3307a1SBoris Brezillon 		mtd->size = (u64)mtd_div_by_eb(mtd->size, master) *
7109e3307a1SBoris Brezillon 			    mtd->erasesize;
7119e3307a1SBoris Brezillon 	}
7129e3307a1SBoris Brezillon 
71369423d99SAdrian Hunter 	if (is_power_of_2(mtd->erasesize))
71469423d99SAdrian Hunter 		mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
71569423d99SAdrian Hunter 	else
71669423d99SAdrian Hunter 		mtd->erasesize_shift = 0;
71769423d99SAdrian Hunter 
71869423d99SAdrian Hunter 	if (is_power_of_2(mtd->writesize))
71969423d99SAdrian Hunter 		mtd->writesize_shift = ffs(mtd->writesize) - 1;
72069423d99SAdrian Hunter 	else
72169423d99SAdrian Hunter 		mtd->writesize_shift = 0;
72269423d99SAdrian Hunter 
72369423d99SAdrian Hunter 	mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
72469423d99SAdrian Hunter 	mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
72569423d99SAdrian Hunter 
726187ef152SHåvard Skinnemoen 	/* Some chips always power up locked. Unlock them now */
72738134565SArtem Bityutskiy 	if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
72838134565SArtem Bityutskiy 		error = mtd_unlock(mtd, 0, mtd->size);
72938134565SArtem Bityutskiy 		if (error && error != -EOPNOTSUPP)
730187ef152SHåvard Skinnemoen 			printk(KERN_WARNING
731b520e412SBen Hutchings 			       "%s: unlock failed, writes may not work\n",
732187ef152SHåvard Skinnemoen 			       mtd->name);
73357dd990cSBrian Norris 		/* Ignore unlock failures? */
73457dd990cSBrian Norris 		error = 0;
735187ef152SHåvard Skinnemoen 	}
736187ef152SHåvard Skinnemoen 
7371f24b5a8SDavid Brownell 	/* Caller should have set dev.parent to match the
738260e89a6SFrans Klaver 	 * physical device, if appropriate.
7391f24b5a8SDavid Brownell 	 */
7401f24b5a8SDavid Brownell 	mtd->dev.type = &mtd_devtype;
74115bce40cSDavid Woodhouse 	mtd->dev.class = &mtd_class;
7421f24b5a8SDavid Brownell 	mtd->dev.devt = MTD_DEVT(i);
7431f24b5a8SDavid Brownell 	dev_set_name(&mtd->dev, "mtd%d", i);
7446afc4fdbSSaeed Bishara 	dev_set_drvdata(&mtd->dev, mtd);
745ad9b10d1SChristian Marangi 	mtd_check_of_node(mtd);
746215a02fdSBrian Norris 	of_node_get(mtd_get_of_node(mtd));
74757dd990cSBrian Norris 	error = device_register(&mtd->dev);
748895d68a3SZhang Xiaoxu 	if (error) {
749895d68a3SZhang Xiaoxu 		put_device(&mtd->dev);
750b520e412SBen Hutchings 		goto fail_added;
751895d68a3SZhang Xiaoxu 	}
7521f24b5a8SDavid Brownell 
753c4dfa25aSAlban Bedel 	/* Add the nvmem provider */
754c4dfa25aSAlban Bedel 	error = mtd_nvmem_add(mtd);
755c4dfa25aSAlban Bedel 	if (error)
756c4dfa25aSAlban Bedel 		goto fail_nvmem_add;
757c4dfa25aSAlban Bedel 
7581018c94bSZhuohao Lee 	mtd_debugfs_populate(mtd);
759e8e3edb9SMario Rugiero 
7605e472128SBrian Norris 	device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
7615e472128SBrian Norris 		      "mtd%dro", i);
7621f24b5a8SDavid Brownell 
763289c0522SBrian Norris 	pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
7641da177e4SLinus Torvalds 	/* No need to get a refcount on the module containing
7651da177e4SLinus Torvalds 	   the notifier, since we hold the mtd_table_mutex */
76671a928c0SChris Malley 	list_for_each_entry(not, &mtd_notifiers, list)
7671da177e4SLinus Torvalds 		not->add(mtd);
7681da177e4SLinus Torvalds 
76948b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
77026422ac7SRafał Miłecki 
77157150c40SRob Herring 	if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
77226422ac7SRafał Miłecki 		if (IS_BUILTIN(CONFIG_MTD)) {
77326422ac7SRafał Miłecki 			pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
77426422ac7SRafał Miłecki 			ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
77526422ac7SRafał Miłecki 		} else {
77626422ac7SRafał Miłecki 			pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n",
77726422ac7SRafał Miłecki 				mtd->index, mtd->name);
77826422ac7SRafał Miłecki 		}
77926422ac7SRafał Miłecki 	}
78026422ac7SRafał Miłecki 
7811da177e4SLinus Torvalds 	/* We _know_ we aren't being removed, because
7821da177e4SLinus Torvalds 	   our caller is still holding us here. So none
7831da177e4SLinus Torvalds 	   of this try_ nonsense, and no bitching about it
7841da177e4SLinus Torvalds 	   either. :) */
7851da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
7861da177e4SLinus Torvalds 	return 0;
7871da177e4SLinus Torvalds 
788c4dfa25aSAlban Bedel fail_nvmem_add:
789c4dfa25aSAlban Bedel 	device_unregister(&mtd->dev);
790b520e412SBen Hutchings fail_added:
791215a02fdSBrian Norris 	of_node_put(mtd_get_of_node(mtd));
792b520e412SBen Hutchings 	idr_remove(&mtd_idr, i);
793b520e412SBen Hutchings fail_locked:
79448b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
79557dd990cSBrian Norris 	return error;
7961da177e4SLinus Torvalds }
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds /**
7991da177e4SLinus Torvalds  *	del_mtd_device - unregister an MTD device
8001da177e4SLinus Torvalds  *	@mtd: pointer to MTD device info structure
8011da177e4SLinus Torvalds  *
8021da177e4SLinus Torvalds  *	Remove a device from the list of MTD devices present in the system,
8031da177e4SLinus Torvalds  *	and notify each currently active MTD 'user' of its departure.
8041da177e4SLinus Torvalds  *	Returns zero on success or 1 on failure, which currently will happen
8051da177e4SLinus Torvalds  *	if the requested device does not appear to be present in the list.
8061da177e4SLinus Torvalds  */
8071da177e4SLinus Torvalds 
del_mtd_device(struct mtd_info * mtd)8081da177e4SLinus Torvalds int del_mtd_device(struct mtd_info *mtd)
8091da177e4SLinus Torvalds {
8101da177e4SLinus Torvalds 	int ret;
81175c0b84dSMaxim Levitsky 	struct mtd_notifier *not;
8121da177e4SLinus Torvalds 
81348b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
8141da177e4SLinus Torvalds 
815b520e412SBen Hutchings 	if (idr_find(&mtd_idr, mtd->index) != mtd) {
8161da177e4SLinus Torvalds 		ret = -ENODEV;
81775c0b84dSMaxim Levitsky 		goto out_error;
81875c0b84dSMaxim Levitsky 	}
819694bb7fcSKevin Cernekee 
8201da177e4SLinus Torvalds 	/* No need to get a refcount on the module containing
8211da177e4SLinus Torvalds 		the notifier, since we hold the mtd_table_mutex */
82271a928c0SChris Malley 	list_for_each_entry(not, &mtd_notifiers, list)
8231da177e4SLinus Torvalds 		not->remove(mtd);
8241da177e4SLinus Torvalds 
82519bfa9ebSTomas Winkler 	kref_put(&mtd->refcnt, mtd_device_release);
8261da177e4SLinus Torvalds 	ret = 0;
8271da177e4SLinus Torvalds 
82875c0b84dSMaxim Levitsky out_error:
82948b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
8301da177e4SLinus Torvalds 	return ret;
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds 
833472b444eSBrian Norris /*
834472b444eSBrian Norris  * Set a few defaults based on the parent devices, if not provided by the
835472b444eSBrian Norris  * driver
836472b444eSBrian Norris  */
mtd_set_dev_defaults(struct mtd_info * mtd)837472b444eSBrian Norris static void mtd_set_dev_defaults(struct mtd_info *mtd)
838472b444eSBrian Norris {
839472b444eSBrian Norris 	if (mtd->dev.parent) {
840472b444eSBrian Norris 		if (!mtd->owner && mtd->dev.parent->driver)
841472b444eSBrian Norris 			mtd->owner = mtd->dev.parent->driver->owner;
842472b444eSBrian Norris 		if (!mtd->name)
843472b444eSBrian Norris 			mtd->name = dev_name(mtd->dev.parent);
844472b444eSBrian Norris 	} else {
845472b444eSBrian Norris 		pr_debug("mtd device won't show a device symlink in sysfs\n");
846472b444eSBrian Norris 	}
8471186af45SRafał Miłecki 
84846b5889cSMiquel Raynal 	INIT_LIST_HEAD(&mtd->partitions);
84946b5889cSMiquel Raynal 	mutex_init(&mtd->master.partitions_lock);
8501ad55288SAlexander Sverdlin 	mutex_init(&mtd->master.chrdev_lock);
851472b444eSBrian Norris }
852727dc612SDan Ehrenberg 
mtd_otp_size(struct mtd_info * mtd,bool is_user)8534b361cfaSMichael Walle static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user)
8544b361cfaSMichael Walle {
855c3c8c051SDan Carpenter 	struct otp_info *info;
8564b361cfaSMichael Walle 	ssize_t size = 0;
8574b361cfaSMichael Walle 	unsigned int i;
8584b361cfaSMichael Walle 	size_t retlen;
8594b361cfaSMichael Walle 	int ret;
8604b361cfaSMichael Walle 
861c3c8c051SDan Carpenter 	info = kmalloc(PAGE_SIZE, GFP_KERNEL);
862c3c8c051SDan Carpenter 	if (!info)
863c3c8c051SDan Carpenter 		return -ENOMEM;
864c3c8c051SDan Carpenter 
8654b361cfaSMichael Walle 	if (is_user)
8664b361cfaSMichael Walle 		ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info);
8674b361cfaSMichael Walle 	else
8684b361cfaSMichael Walle 		ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info);
8694b361cfaSMichael Walle 	if (ret)
8704b361cfaSMichael Walle 		goto err;
8714b361cfaSMichael Walle 
872bc8e157fSJon Hunter 	for (i = 0; i < retlen / sizeof(*info); i++)
873bc8e157fSJon Hunter 		size += info[i].length;
8744b361cfaSMichael Walle 
8754b361cfaSMichael Walle 	kfree(info);
8764b361cfaSMichael Walle 	return size;
8774b361cfaSMichael Walle 
8784b361cfaSMichael Walle err:
8794b361cfaSMichael Walle 	kfree(info);
88045bb1faaSMichael Walle 
88145bb1faaSMichael Walle 	/* ENODATA means there is no OTP region. */
88245bb1faaSMichael Walle 	return ret == -ENODATA ? 0 : ret;
8834b361cfaSMichael Walle }
8844b361cfaSMichael Walle 
mtd_otp_nvmem_register(struct mtd_info * mtd,const char * compatible,int size,nvmem_reg_read_t reg_read)8854b361cfaSMichael Walle static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
8864b361cfaSMichael Walle 						   const char *compatible,
8874b361cfaSMichael Walle 						   int size,
8884b361cfaSMichael Walle 						   nvmem_reg_read_t reg_read)
8894b361cfaSMichael Walle {
8904b361cfaSMichael Walle 	struct nvmem_device *nvmem = NULL;
8914b361cfaSMichael Walle 	struct nvmem_config config = {};
8924b361cfaSMichael Walle 	struct device_node *np;
8934b361cfaSMichael Walle 
8944b361cfaSMichael Walle 	/* DT binding is optional */
8954b361cfaSMichael Walle 	np = of_get_compatible_child(mtd->dev.of_node, compatible);
8964b361cfaSMichael Walle 
8974b361cfaSMichael Walle 	/* OTP nvmem will be registered on the physical device */
8984b361cfaSMichael Walle 	config.dev = mtd->dev.parent;
8991cd9ceaaSMichael Walle 	config.name = compatible;
9001cd9ceaaSMichael Walle 	config.id = NVMEM_DEVID_AUTO;
9014b361cfaSMichael Walle 	config.owner = THIS_MODULE;
902cce311f8SChristian Marangi 	config.add_legacy_fixed_of_cells = !mtd_type_is_nand(mtd);
9034b361cfaSMichael Walle 	config.type = NVMEM_TYPE_OTP;
9044b361cfaSMichael Walle 	config.root_only = true;
9056c762189SChristophe Kerello 	config.ignore_wp = true;
9064b361cfaSMichael Walle 	config.reg_read = reg_read;
9074b361cfaSMichael Walle 	config.size = size;
9084b361cfaSMichael Walle 	config.of_node = np;
9094b361cfaSMichael Walle 	config.priv = mtd;
9104b361cfaSMichael Walle 
9114b361cfaSMichael Walle 	nvmem = nvmem_register(&config);
9124b361cfaSMichael Walle 	/* Just ignore if there is no NVMEM support in the kernel */
9134b361cfaSMichael Walle 	if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP)
9144b361cfaSMichael Walle 		nvmem = NULL;
9154b361cfaSMichael Walle 
9164b361cfaSMichael Walle 	of_node_put(np);
9174b361cfaSMichael Walle 
9184b361cfaSMichael Walle 	return nvmem;
9194b361cfaSMichael Walle }
9204b361cfaSMichael Walle 
mtd_nvmem_user_otp_reg_read(void * priv,unsigned int offset,void * val,size_t bytes)9214b361cfaSMichael Walle static int mtd_nvmem_user_otp_reg_read(void *priv, unsigned int offset,
9224b361cfaSMichael Walle 				       void *val, size_t bytes)
9234b361cfaSMichael Walle {
9244b361cfaSMichael Walle 	struct mtd_info *mtd = priv;
9254b361cfaSMichael Walle 	size_t retlen;
9264b361cfaSMichael Walle 	int ret;
9274b361cfaSMichael Walle 
9284b361cfaSMichael Walle 	ret = mtd_read_user_prot_reg(mtd, offset, bytes, &retlen, val);
9294b361cfaSMichael Walle 	if (ret)
9304b361cfaSMichael Walle 		return ret;
9314b361cfaSMichael Walle 
9324b361cfaSMichael Walle 	return retlen == bytes ? 0 : -EIO;
9334b361cfaSMichael Walle }
9344b361cfaSMichael Walle 
mtd_nvmem_fact_otp_reg_read(void * priv,unsigned int offset,void * val,size_t bytes)9354b361cfaSMichael Walle static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
9364b361cfaSMichael Walle 				       void *val, size_t bytes)
9374b361cfaSMichael Walle {
9384b361cfaSMichael Walle 	struct mtd_info *mtd = priv;
9394b361cfaSMichael Walle 	size_t retlen;
9404b361cfaSMichael Walle 	int ret;
9414b361cfaSMichael Walle 
9424b361cfaSMichael Walle 	ret = mtd_read_fact_prot_reg(mtd, offset, bytes, &retlen, val);
9434b361cfaSMichael Walle 	if (ret)
9444b361cfaSMichael Walle 		return ret;
9454b361cfaSMichael Walle 
9464b361cfaSMichael Walle 	return retlen == bytes ? 0 : -EIO;
9474b361cfaSMichael Walle }
9484b361cfaSMichael Walle 
mtd_otp_nvmem_add(struct mtd_info * mtd)9494b361cfaSMichael Walle static int mtd_otp_nvmem_add(struct mtd_info *mtd)
9504b361cfaSMichael Walle {
9518bd1d24eSMichael Walle 	struct device *dev = mtd->dev.parent;
9524b361cfaSMichael Walle 	struct nvmem_device *nvmem;
9534b361cfaSMichael Walle 	ssize_t size;
9544b361cfaSMichael Walle 	int err;
9554b361cfaSMichael Walle 
9564b361cfaSMichael Walle 	if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) {
9574b361cfaSMichael Walle 		size = mtd_otp_size(mtd, true);
958*adbd5da0SAapo Vienamo 		if (size < 0) {
959*adbd5da0SAapo Vienamo 			err = size;
960*adbd5da0SAapo Vienamo 			goto err;
961*adbd5da0SAapo Vienamo 		}
9624b361cfaSMichael Walle 
9634b361cfaSMichael Walle 		if (size > 0) {
9644b361cfaSMichael Walle 			nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size,
9654b361cfaSMichael Walle 						       mtd_nvmem_user_otp_reg_read);
9664b361cfaSMichael Walle 			if (IS_ERR(nvmem)) {
967281f7a6cSMichael Walle 				err = PTR_ERR(nvmem);
968281f7a6cSMichael Walle 				goto err;
9694b361cfaSMichael Walle 			}
9704b361cfaSMichael Walle 			mtd->otp_user_nvmem = nvmem;
9714b361cfaSMichael Walle 		}
9724b361cfaSMichael Walle 	}
9734b361cfaSMichael Walle 
9744b361cfaSMichael Walle 	if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) {
9754b361cfaSMichael Walle 		size = mtd_otp_size(mtd, false);
9764b361cfaSMichael Walle 		if (size < 0) {
9774b361cfaSMichael Walle 			err = size;
9784b361cfaSMichael Walle 			goto err;
9794b361cfaSMichael Walle 		}
9804b361cfaSMichael Walle 
9814b361cfaSMichael Walle 		if (size > 0) {
9823b270facSLinus Walleij 			/*
9833b270facSLinus Walleij 			 * The factory OTP contains thing such as a unique serial
9843b270facSLinus Walleij 			 * number and is small, so let's read it out and put it
9853b270facSLinus Walleij 			 * into the entropy pool.
9863b270facSLinus Walleij 			 */
9873b270facSLinus Walleij 			void *otp;
9883b270facSLinus Walleij 
9893b270facSLinus Walleij 			otp = kmalloc(size, GFP_KERNEL);
990cefa1aaaSDan Carpenter 			if (!otp) {
991cefa1aaaSDan Carpenter 				err = -ENOMEM;
992cefa1aaaSDan Carpenter 				goto err;
993cefa1aaaSDan Carpenter 			}
9943b270facSLinus Walleij 			err = mtd_nvmem_fact_otp_reg_read(mtd, 0, otp, size);
9953b270facSLinus Walleij 			if (err < 0) {
9963b270facSLinus Walleij 				kfree(otp);
997cefa1aaaSDan Carpenter 				goto err;
9983b270facSLinus Walleij 			}
9993b270facSLinus Walleij 			add_device_randomness(otp, err);
10003b270facSLinus Walleij 			kfree(otp);
10013b270facSLinus Walleij 
10024b361cfaSMichael Walle 			nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size,
10034b361cfaSMichael Walle 						       mtd_nvmem_fact_otp_reg_read);
10044b361cfaSMichael Walle 			if (IS_ERR(nvmem)) {
10054b361cfaSMichael Walle 				err = PTR_ERR(nvmem);
10064b361cfaSMichael Walle 				goto err;
10074b361cfaSMichael Walle 			}
10084b361cfaSMichael Walle 			mtd->otp_factory_nvmem = nvmem;
10094b361cfaSMichael Walle 		}
10104b361cfaSMichael Walle 	}
10114b361cfaSMichael Walle 
10124b361cfaSMichael Walle 	return 0;
10134b361cfaSMichael Walle 
10144b361cfaSMichael Walle err:
10154b361cfaSMichael Walle 	nvmem_unregister(mtd->otp_user_nvmem);
1016281f7a6cSMichael Walle 	return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n");
10174b361cfaSMichael Walle }
10184b361cfaSMichael Walle 
10191da177e4SLinus Torvalds /**
10201c4c215cSDmitry Eremin-Solenikov  * mtd_device_parse_register - parse partitions and register an MTD device.
10211c4c215cSDmitry Eremin-Solenikov  *
10221c4c215cSDmitry Eremin-Solenikov  * @mtd: the MTD device to register
10231c4c215cSDmitry Eremin-Solenikov  * @types: the list of MTD partition probes to try, see
10241c4c215cSDmitry Eremin-Solenikov  *         'parse_mtd_partitions()' for more information
1025c7975330SDmitry Eremin-Solenikov  * @parser_data: MTD partition parser-specific data
10261c4c215cSDmitry Eremin-Solenikov  * @parts: fallback partition information to register, if parsing fails;
10271c4c215cSDmitry Eremin-Solenikov  *         only valid if %nr_parts > %0
10281c4c215cSDmitry Eremin-Solenikov  * @nr_parts: the number of partitions in parts, if zero then the full
10291c4c215cSDmitry Eremin-Solenikov  *            MTD device is registered if no partition info is found
10301c4c215cSDmitry Eremin-Solenikov  *
10311c4c215cSDmitry Eremin-Solenikov  * This function aggregates MTD partitions parsing (done by
10321c4c215cSDmitry Eremin-Solenikov  * 'parse_mtd_partitions()') and MTD device and partitions registering. It
10331c4c215cSDmitry Eremin-Solenikov  * basically follows the most common pattern found in many MTD drivers:
10341c4c215cSDmitry Eremin-Solenikov  *
103555a999a0SRafał Miłecki  * * If the MTD_PARTITIONED_MASTER option is set, then the device as a whole is
103655a999a0SRafał Miłecki  *   registered first.
103755a999a0SRafał Miłecki  * * Then It tries to probe partitions on MTD device @mtd using parsers
10381c4c215cSDmitry Eremin-Solenikov  *   specified in @types (if @types is %NULL, then the default list of parsers
10391c4c215cSDmitry Eremin-Solenikov  *   is used, see 'parse_mtd_partitions()' for more information). If none are
10401c4c215cSDmitry Eremin-Solenikov  *   found this functions tries to fallback to information specified in
10411c4c215cSDmitry Eremin-Solenikov  *   @parts/@nr_parts.
10421c4c215cSDmitry Eremin-Solenikov  * * If no partitions were found this function just registers the MTD device
10431c4c215cSDmitry Eremin-Solenikov  *   @mtd and exits.
10441c4c215cSDmitry Eremin-Solenikov  *
10451c4c215cSDmitry Eremin-Solenikov  * Returns zero in case of success and a negative error code in case of failure.
10461c4c215cSDmitry Eremin-Solenikov  */
mtd_device_parse_register(struct mtd_info * mtd,const char * const * types,struct mtd_part_parser_data * parser_data,const struct mtd_partition * parts,int nr_parts)104726a47346SArtem Bityutskiy int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
1048c7975330SDmitry Eremin-Solenikov 			      struct mtd_part_parser_data *parser_data,
10491c4c215cSDmitry Eremin-Solenikov 			      const struct mtd_partition *parts,
10501c4c215cSDmitry Eremin-Solenikov 			      int nr_parts)
10511c4c215cSDmitry Eremin-Solenikov {
1052727dc612SDan Ehrenberg 	int ret;
10531c4c215cSDmitry Eremin-Solenikov 
1054472b444eSBrian Norris 	mtd_set_dev_defaults(mtd);
1055472b444eSBrian Norris 
1056e0489f6eSMichael Walle 	ret = mtd_otp_nvmem_add(mtd);
1057e0489f6eSMichael Walle 	if (ret)
1058e0489f6eSMichael Walle 		goto out;
1059e0489f6eSMichael Walle 
10602c77c57dSRafał Miłecki 	if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
10612c77c57dSRafał Miłecki 		ret = add_mtd_device(mtd);
10622c77c57dSRafał Miłecki 		if (ret)
1063e0489f6eSMichael Walle 			goto out;
10642c77c57dSRafał Miłecki 	}
10652c77c57dSRafał Miłecki 
10660dbe4ea7SRafał Miłecki 	/* Prefer parsed partitions over driver-provided fallback */
10675ac67ce3SRafał Miłecki 	ret = parse_mtd_partitions(mtd, types, parser_data);
106808608adbSManivannan Sadhasivam 	if (ret == -EPROBE_DEFER)
106908608adbSManivannan Sadhasivam 		goto out;
107008608adbSManivannan Sadhasivam 
10715ac67ce3SRafał Miłecki 	if (ret > 0)
10725ac67ce3SRafał Miłecki 		ret = 0;
10735ac67ce3SRafał Miłecki 	else if (nr_parts)
10740dbe4ea7SRafał Miłecki 		ret = add_mtd_partitions(mtd, parts, nr_parts);
10750dbe4ea7SRafał Miłecki 	else if (!device_is_registered(&mtd->dev))
10760dbe4ea7SRafał Miłecki 		ret = add_mtd_device(mtd);
10770dbe4ea7SRafał Miłecki 	else
10780dbe4ea7SRafał Miłecki 		ret = 0;
10790dbe4ea7SRafał Miłecki 
10803e00ed0eSBrian Norris 	if (ret)
10813e00ed0eSBrian Norris 		goto out;
10821c4c215cSDmitry Eremin-Solenikov 
1083e1dd8641SNiklas Cassel 	/*
1084e1dd8641SNiklas Cassel 	 * FIXME: some drivers unfortunately call this function more than once.
1085e1dd8641SNiklas Cassel 	 * So we have to check if we've already assigned the reboot notifier.
1086e1dd8641SNiklas Cassel 	 *
1087e1dd8641SNiklas Cassel 	 * Generally, we can make multiple calls work for most cases, but it
1088e1dd8641SNiklas Cassel 	 * does cause problems with parse_mtd_partitions() above (e.g.,
1089e1dd8641SNiklas Cassel 	 * cmdlineparts will register partitions more than once).
1090e1dd8641SNiklas Cassel 	 */
1091f8479dd6SBrian Norris 	WARN_ONCE(mtd->_reboot && mtd->reboot_notifier.notifier_call,
1092f8479dd6SBrian Norris 		  "MTD already registered\n");
1093e1dd8641SNiklas Cassel 	if (mtd->_reboot && !mtd->reboot_notifier.notifier_call) {
10943efe41beSBrian Norris 		mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
10953efe41beSBrian Norris 		register_reboot_notifier(&mtd->reboot_notifier);
10963efe41beSBrian Norris 	}
10973efe41beSBrian Norris 
10983e00ed0eSBrian Norris out:
1099e0489f6eSMichael Walle 	if (ret) {
1100e0489f6eSMichael Walle 		nvmem_unregister(mtd->otp_user_nvmem);
1101e0489f6eSMichael Walle 		nvmem_unregister(mtd->otp_factory_nvmem);
1102e0489f6eSMichael Walle 	}
1103e0489f6eSMichael Walle 
11042c77c57dSRafał Miłecki 	if (ret && device_is_registered(&mtd->dev))
11052c77c57dSRafał Miłecki 		del_mtd_device(mtd);
11062c77c57dSRafał Miłecki 
1107727dc612SDan Ehrenberg 	return ret;
11081c4c215cSDmitry Eremin-Solenikov }
11091c4c215cSDmitry Eremin-Solenikov EXPORT_SYMBOL_GPL(mtd_device_parse_register);
11101c4c215cSDmitry Eremin-Solenikov 
11111c4c215cSDmitry Eremin-Solenikov /**
1112f5671ab3SJamie Iles  * mtd_device_unregister - unregister an existing MTD device.
1113f5671ab3SJamie Iles  *
1114f5671ab3SJamie Iles  * @master: the MTD device to unregister.  This will unregister both the master
1115f5671ab3SJamie Iles  *          and any partitions if registered.
1116f5671ab3SJamie Iles  */
mtd_device_unregister(struct mtd_info * master)1117f5671ab3SJamie Iles int mtd_device_unregister(struct mtd_info *master)
1118f5671ab3SJamie Iles {
1119f5671ab3SJamie Iles 	int err;
1120f5671ab3SJamie Iles 
112100596576SZev Weiss 	if (master->_reboot) {
11223efe41beSBrian Norris 		unregister_reboot_notifier(&master->reboot_notifier);
112300596576SZev Weiss 		memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier));
112400596576SZev Weiss 	}
11253efe41beSBrian Norris 
11264b361cfaSMichael Walle 	nvmem_unregister(master->otp_user_nvmem);
11274b361cfaSMichael Walle 	nvmem_unregister(master->otp_factory_nvmem);
11284b361cfaSMichael Walle 
1129f5671ab3SJamie Iles 	err = del_mtd_partitions(master);
1130f5671ab3SJamie Iles 	if (err)
1131f5671ab3SJamie Iles 		return err;
1132f5671ab3SJamie Iles 
1133f5671ab3SJamie Iles 	if (!device_is_registered(&master->dev))
1134f5671ab3SJamie Iles 		return 0;
1135f5671ab3SJamie Iles 
1136f5671ab3SJamie Iles 	return del_mtd_device(master);
1137f5671ab3SJamie Iles }
1138f5671ab3SJamie Iles EXPORT_SYMBOL_GPL(mtd_device_unregister);
1139f5671ab3SJamie Iles 
1140f5671ab3SJamie Iles /**
11411da177e4SLinus Torvalds  *	register_mtd_user - register a 'user' of MTD devices.
11421da177e4SLinus Torvalds  *	@new: pointer to notifier info structure
11431da177e4SLinus Torvalds  *
11441da177e4SLinus Torvalds  *	Registers a pair of callbacks function to be called upon addition
11451da177e4SLinus Torvalds  *	or removal of MTD devices. Causes the 'add' callback to be immediately
11461da177e4SLinus Torvalds  *	invoked for each MTD device currently present in the system.
11471da177e4SLinus Torvalds  */
register_mtd_user(struct mtd_notifier * new)11481da177e4SLinus Torvalds void register_mtd_user (struct mtd_notifier *new)
11491da177e4SLinus Torvalds {
1150f1332ba2SBen Hutchings 	struct mtd_info *mtd;
11511da177e4SLinus Torvalds 
115248b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds 	list_add(&new->list, &mtd_notifiers);
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
11571da177e4SLinus Torvalds 
1158f1332ba2SBen Hutchings 	mtd_for_each_device(mtd)
1159f1332ba2SBen Hutchings 		new->add(mtd);
11601da177e4SLinus Torvalds 
116148b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
11621da177e4SLinus Torvalds }
116333c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(register_mtd_user);
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds /**
116649450795SArtem B. Bityuckiy  *	unregister_mtd_user - unregister a 'user' of MTD devices.
116749450795SArtem B. Bityuckiy  *	@old: pointer to notifier info structure
11681da177e4SLinus Torvalds  *
11691da177e4SLinus Torvalds  *	Removes a callback function pair from the list of 'users' to be
11701da177e4SLinus Torvalds  *	notified upon addition or removal of MTD devices. Causes the
11711da177e4SLinus Torvalds  *	'remove' callback to be immediately invoked for each MTD device
11721da177e4SLinus Torvalds  *	currently present in the system.
11731da177e4SLinus Torvalds  */
unregister_mtd_user(struct mtd_notifier * old)11741da177e4SLinus Torvalds int unregister_mtd_user (struct mtd_notifier *old)
11751da177e4SLinus Torvalds {
1176f1332ba2SBen Hutchings 	struct mtd_info *mtd;
11771da177e4SLinus Torvalds 
117848b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	module_put(THIS_MODULE);
11811da177e4SLinus Torvalds 
1182f1332ba2SBen Hutchings 	mtd_for_each_device(mtd)
1183f1332ba2SBen Hutchings 		old->remove(mtd);
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds 	list_del(&old->list);
118648b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
11871da177e4SLinus Torvalds 	return 0;
11881da177e4SLinus Torvalds }
118933c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(unregister_mtd_user);
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds /**
11921da177e4SLinus Torvalds  *	get_mtd_device - obtain a validated handle for an MTD device
11931da177e4SLinus Torvalds  *	@mtd: last known address of the required MTD device
11941da177e4SLinus Torvalds  *	@num: internal device number of the required MTD device
11951da177e4SLinus Torvalds  *
11961da177e4SLinus Torvalds  *	Given a number and NULL address, return the num'th entry in the device
11971da177e4SLinus Torvalds  *	table, if any.	Given an address and num == -1, search the device table
11981da177e4SLinus Torvalds  *	for a device with that address and return if it's still present. Given
11999c74034fSArtem Bityutskiy  *	both, return the num'th driver only if its address matches. Return
12009c74034fSArtem Bityutskiy  *	error code if not.
12011da177e4SLinus Torvalds  */
get_mtd_device(struct mtd_info * mtd,int num)12021da177e4SLinus Torvalds struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
12031da177e4SLinus Torvalds {
1204f1332ba2SBen Hutchings 	struct mtd_info *ret = NULL, *other;
1205f1332ba2SBen Hutchings 	int err = -ENODEV;
12061da177e4SLinus Torvalds 
120748b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	if (num == -1) {
1210f1332ba2SBen Hutchings 		mtd_for_each_device(other) {
1211f1332ba2SBen Hutchings 			if (other == mtd) {
1212f1332ba2SBen Hutchings 				ret = mtd;
1213f1332ba2SBen Hutchings 				break;
1214f1332ba2SBen Hutchings 			}
1215f1332ba2SBen Hutchings 		}
1216b520e412SBen Hutchings 	} else if (num >= 0) {
1217b520e412SBen Hutchings 		ret = idr_find(&mtd_idr, num);
12181da177e4SLinus Torvalds 		if (mtd && mtd != ret)
12191da177e4SLinus Torvalds 			ret = NULL;
12201da177e4SLinus Torvalds 	}
12211da177e4SLinus Torvalds 
12223bd45657SMaxim Levitsky 	if (!ret) {
12233bd45657SMaxim Levitsky 		ret = ERR_PTR(err);
12243bd45657SMaxim Levitsky 		goto out;
12259fe912ceSArtem Bityutskiy 	}
12269fe912ceSArtem Bityutskiy 
12273bd45657SMaxim Levitsky 	err = __get_mtd_device(ret);
12283bd45657SMaxim Levitsky 	if (err)
12293bd45657SMaxim Levitsky 		ret = ERR_PTR(err);
12303bd45657SMaxim Levitsky out:
123148b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
12321da177e4SLinus Torvalds 	return ret;
12333bd45657SMaxim Levitsky }
123433c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(get_mtd_device);
12359c74034fSArtem Bityutskiy 
12363bd45657SMaxim Levitsky 
__get_mtd_device(struct mtd_info * mtd)12373bd45657SMaxim Levitsky int __get_mtd_device(struct mtd_info *mtd)
12383bd45657SMaxim Levitsky {
123946b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
12403bd45657SMaxim Levitsky 	int err;
12413bd45657SMaxim Levitsky 
124246b5889cSMiquel Raynal 	if (master->_get_device) {
124346b5889cSMiquel Raynal 		err = master->_get_device(mtd);
124479c4a562SAlexander Usyskin 		if (err)
12453bd45657SMaxim Levitsky 			return err;
12463bd45657SMaxim Levitsky 	}
124779c4a562SAlexander Usyskin 
124879c4a562SAlexander Usyskin 	if (!try_module_get(master->owner)) {
124979c4a562SAlexander Usyskin 		if (master->_put_device)
125079c4a562SAlexander Usyskin 			master->_put_device(master);
125179c4a562SAlexander Usyskin 		return -ENODEV;
12523bd45657SMaxim Levitsky 	}
125346b5889cSMiquel Raynal 
1254264725e3SMiquel Raynal 	while (mtd) {
1255264725e3SMiquel Raynal 		if (mtd != master)
125679c4a562SAlexander Usyskin 			kref_get(&mtd->refcnt);
125746b5889cSMiquel Raynal 		mtd = mtd->parent;
125846b5889cSMiquel Raynal 	}
125946b5889cSMiquel Raynal 
1260264725e3SMiquel Raynal 	if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
1261264725e3SMiquel Raynal 		kref_get(&master->refcnt);
1262264725e3SMiquel Raynal 
12633bd45657SMaxim Levitsky 	return 0;
12641da177e4SLinus Torvalds }
126533c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(__get_mtd_device);
12661da177e4SLinus Torvalds 
12677799308fSArtem Bityutskiy /**
12684a575865SRafał Miłecki  * of_get_mtd_device_by_node - obtain an MTD device associated with a given node
12694a575865SRafał Miłecki  *
12704a575865SRafał Miłecki  * @np: device tree node
12714a575865SRafał Miłecki  */
of_get_mtd_device_by_node(struct device_node * np)12724a575865SRafał Miłecki struct mtd_info *of_get_mtd_device_by_node(struct device_node *np)
12734a575865SRafał Miłecki {
12744a575865SRafał Miłecki 	struct mtd_info *mtd = NULL;
12754a575865SRafał Miłecki 	struct mtd_info *tmp;
12764a575865SRafał Miłecki 	int err;
12774a575865SRafał Miłecki 
12784a575865SRafał Miłecki 	mutex_lock(&mtd_table_mutex);
12794a575865SRafał Miłecki 
12804a575865SRafał Miłecki 	err = -EPROBE_DEFER;
12814a575865SRafał Miłecki 	mtd_for_each_device(tmp) {
12824a575865SRafał Miłecki 		if (mtd_get_of_node(tmp) == np) {
12834a575865SRafał Miłecki 			mtd = tmp;
12844a575865SRafał Miłecki 			err = __get_mtd_device(mtd);
12854a575865SRafał Miłecki 			break;
12864a575865SRafał Miłecki 		}
12874a575865SRafał Miłecki 	}
12884a575865SRafał Miłecki 
12894a575865SRafał Miłecki 	mutex_unlock(&mtd_table_mutex);
12904a575865SRafał Miłecki 
12914a575865SRafał Miłecki 	return err ? ERR_PTR(err) : mtd;
12924a575865SRafał Miłecki }
12934a575865SRafał Miłecki EXPORT_SYMBOL_GPL(of_get_mtd_device_by_node);
12944a575865SRafał Miłecki 
12954a575865SRafał Miłecki /**
12967799308fSArtem Bityutskiy  *	get_mtd_device_nm - obtain a validated handle for an MTD device by
12977799308fSArtem Bityutskiy  *	device name
12987799308fSArtem Bityutskiy  *	@name: MTD device name to open
12997799308fSArtem Bityutskiy  *
13007799308fSArtem Bityutskiy  * 	This function returns MTD device description structure in case of
13017799308fSArtem Bityutskiy  * 	success and an error code in case of failure.
13027799308fSArtem Bityutskiy  */
get_mtd_device_nm(const char * name)13037799308fSArtem Bityutskiy struct mtd_info *get_mtd_device_nm(const char *name)
13047799308fSArtem Bityutskiy {
1305f1332ba2SBen Hutchings 	int err = -ENODEV;
1306f1332ba2SBen Hutchings 	struct mtd_info *mtd = NULL, *other;
13077799308fSArtem Bityutskiy 
13087799308fSArtem Bityutskiy 	mutex_lock(&mtd_table_mutex);
13097799308fSArtem Bityutskiy 
1310f1332ba2SBen Hutchings 	mtd_for_each_device(other) {
1311f1332ba2SBen Hutchings 		if (!strcmp(name, other->name)) {
1312f1332ba2SBen Hutchings 			mtd = other;
13137799308fSArtem Bityutskiy 			break;
13147799308fSArtem Bityutskiy 		}
13157799308fSArtem Bityutskiy 	}
13167799308fSArtem Bityutskiy 
13179fe912ceSArtem Bityutskiy 	if (!mtd)
13187799308fSArtem Bityutskiy 		goto out_unlock;
13197799308fSArtem Bityutskiy 
132052534f2dSWanlong Gao 	err = __get_mtd_device(mtd);
132152534f2dSWanlong Gao 	if (err)
13227799308fSArtem Bityutskiy 		goto out_unlock;
13237799308fSArtem Bityutskiy 
13247799308fSArtem Bityutskiy 	mutex_unlock(&mtd_table_mutex);
13257799308fSArtem Bityutskiy 	return mtd;
13269fe912ceSArtem Bityutskiy 
13279fe912ceSArtem Bityutskiy out_unlock:
13289fe912ceSArtem Bityutskiy 	mutex_unlock(&mtd_table_mutex);
13299fe912ceSArtem Bityutskiy 	return ERR_PTR(err);
13307799308fSArtem Bityutskiy }
133133c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(get_mtd_device_nm);
13327799308fSArtem Bityutskiy 
put_mtd_device(struct mtd_info * mtd)13331da177e4SLinus Torvalds void put_mtd_device(struct mtd_info *mtd)
13341da177e4SLinus Torvalds {
133548b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
13363bd45657SMaxim Levitsky 	__put_mtd_device(mtd);
13373bd45657SMaxim Levitsky 	mutex_unlock(&mtd_table_mutex);
13383bd45657SMaxim Levitsky 
13393bd45657SMaxim Levitsky }
134033c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(put_mtd_device);
13413bd45657SMaxim Levitsky 
__put_mtd_device(struct mtd_info * mtd)13423bd45657SMaxim Levitsky void __put_mtd_device(struct mtd_info *mtd)
13433bd45657SMaxim Levitsky {
134446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
134546b5889cSMiquel Raynal 
1346264725e3SMiquel Raynal 	while (mtd) {
1347264725e3SMiquel Raynal 		/* kref_put() can relese mtd, so keep a reference mtd->parent */
134819bfa9ebSTomas Winkler 		struct mtd_info *parent = mtd->parent;
13493bd45657SMaxim Levitsky 
1350264725e3SMiquel Raynal 		if (mtd != master)
135119bfa9ebSTomas Winkler 			kref_put(&mtd->refcnt, mtd_device_release);
135219bfa9ebSTomas Winkler 		mtd = parent;
135319bfa9ebSTomas Winkler 	}
13541ca71415SRichard Weinberger 
135579c4a562SAlexander Usyskin 	if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
135679c4a562SAlexander Usyskin 		kref_put(&master->refcnt, mtd_device_release);
13571da177e4SLinus Torvalds 
135846b5889cSMiquel Raynal 	module_put(master->owner);
135919bfa9ebSTomas Winkler 
136079c4a562SAlexander Usyskin 	/* must be the last as master can be freed in the _put_device */
136179c4a562SAlexander Usyskin 	if (master->_put_device)
136279c4a562SAlexander Usyskin 		master->_put_device(master);
13631da177e4SLinus Torvalds }
136433c87b4aSArtem Bityutskiy EXPORT_SYMBOL_GPL(__put_mtd_device);
13651da177e4SLinus Torvalds 
136652b02031SArtem Bityutskiy /*
1367884cfd90SBoris Brezillon  * Erase is an synchronous operation. Device drivers are epected to return a
1368884cfd90SBoris Brezillon  * negative error code if the operation failed and update instr->fail_addr
1369884cfd90SBoris Brezillon  * to point the portion that was not properly erased.
13708273a0c9SArtem Bityutskiy  */
mtd_erase(struct mtd_info * mtd,struct erase_info * instr)13718273a0c9SArtem Bityutskiy int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
13728273a0c9SArtem Bityutskiy {
137346b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
137446b5889cSMiquel Raynal 	u64 mst_ofs = mtd_get_master_ofs(mtd, 0);
13759e3307a1SBoris Brezillon 	struct erase_info adjinstr;
137646b5889cSMiquel Raynal 	int ret;
137746b5889cSMiquel Raynal 
1378c585da9fSBoris Brezillon 	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
13799e3307a1SBoris Brezillon 	adjinstr = *instr;
1380c585da9fSBoris Brezillon 
138146b5889cSMiquel Raynal 	if (!mtd->erasesize || !master->_erase)
1382e6e620f0SBoris Brezillon 		return -ENOTSUPP;
1383e6e620f0SBoris Brezillon 
13840c2b4e21SBrian Norris 	if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
13858273a0c9SArtem Bityutskiy 		return -EINVAL;
1386664addc2SArtem Bityutskiy 	if (!(mtd->flags & MTD_WRITEABLE))
1387664addc2SArtem Bityutskiy 		return -EROFS;
1388e6e620f0SBoris Brezillon 
1389e7bfb3fdSBoris Brezillon 	if (!instr->len)
1390bcb1d238SArtem Bityutskiy 		return 0;
1391e7bfb3fdSBoris Brezillon 
1392fea728c0SEzequiel Garcia 	ledtrig_mtd_activity();
139346b5889cSMiquel Raynal 
13949e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
13959e3307a1SBoris Brezillon 		adjinstr.addr = (loff_t)mtd_div_by_eb(instr->addr, mtd) *
13969e3307a1SBoris Brezillon 				master->erasesize;
13979e3307a1SBoris Brezillon 		adjinstr.len = ((u64)mtd_div_by_eb(instr->addr + instr->len, mtd) *
13989e3307a1SBoris Brezillon 				master->erasesize) -
13999e3307a1SBoris Brezillon 			       adjinstr.addr;
14009e3307a1SBoris Brezillon 	}
140146b5889cSMiquel Raynal 
14029e3307a1SBoris Brezillon 	adjinstr.addr += mst_ofs;
14039e3307a1SBoris Brezillon 
14049e3307a1SBoris Brezillon 	ret = master->_erase(master, &adjinstr);
14059e3307a1SBoris Brezillon 
14069e3307a1SBoris Brezillon 	if (adjinstr.fail_addr != MTD_FAIL_ADDR_UNKNOWN) {
14079e3307a1SBoris Brezillon 		instr->fail_addr = adjinstr.fail_addr - mst_ofs;
14089e3307a1SBoris Brezillon 		if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
14099e3307a1SBoris Brezillon 			instr->fail_addr = mtd_div_by_eb(instr->fail_addr,
14109e3307a1SBoris Brezillon 							 master);
14119e3307a1SBoris Brezillon 			instr->fail_addr *= mtd->erasesize;
14129e3307a1SBoris Brezillon 		}
14139e3307a1SBoris Brezillon 	}
14149e3307a1SBoris Brezillon 
141546b5889cSMiquel Raynal 	return ret;
14168273a0c9SArtem Bityutskiy }
14178273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_erase);
14188273a0c9SArtem Bityutskiy 
14198273a0c9SArtem Bityutskiy /*
14208273a0c9SArtem Bityutskiy  * This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
14218273a0c9SArtem Bityutskiy  */
mtd_point(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,void ** virt,resource_size_t * phys)14228273a0c9SArtem Bityutskiy int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
14238273a0c9SArtem Bityutskiy 	      void **virt, resource_size_t *phys)
14248273a0c9SArtem Bityutskiy {
142546b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
142646b5889cSMiquel Raynal 
14278273a0c9SArtem Bityutskiy 	*retlen = 0;
14280dd5235fSArtem Bityutskiy 	*virt = NULL;
14290dd5235fSArtem Bityutskiy 	if (phys)
14300dd5235fSArtem Bityutskiy 		*phys = 0;
143146b5889cSMiquel Raynal 	if (!master->_point)
14328273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
14330c2b4e21SBrian Norris 	if (from < 0 || from >= mtd->size || len > mtd->size - from)
14348273a0c9SArtem Bityutskiy 		return -EINVAL;
1435bcb1d238SArtem Bityutskiy 	if (!len)
1436bcb1d238SArtem Bityutskiy 		return 0;
143746b5889cSMiquel Raynal 
143846b5889cSMiquel Raynal 	from = mtd_get_master_ofs(mtd, from);
143946b5889cSMiquel Raynal 	return master->_point(master, from, len, retlen, virt, phys);
14408273a0c9SArtem Bityutskiy }
14418273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_point);
14428273a0c9SArtem Bityutskiy 
14438273a0c9SArtem Bityutskiy /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
mtd_unpoint(struct mtd_info * mtd,loff_t from,size_t len)14448273a0c9SArtem Bityutskiy int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
14458273a0c9SArtem Bityutskiy {
144646b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
144746b5889cSMiquel Raynal 
144846b5889cSMiquel Raynal 	if (!master->_unpoint)
14498273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
14500c2b4e21SBrian Norris 	if (from < 0 || from >= mtd->size || len > mtd->size - from)
14518273a0c9SArtem Bityutskiy 		return -EINVAL;
1452bcb1d238SArtem Bityutskiy 	if (!len)
1453bcb1d238SArtem Bityutskiy 		return 0;
145446b5889cSMiquel Raynal 	return master->_unpoint(master, mtd_get_master_ofs(mtd, from), len);
14558273a0c9SArtem Bityutskiy }
14568273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_unpoint);
14578273a0c9SArtem Bityutskiy 
14588273a0c9SArtem Bityutskiy /*
14598273a0c9SArtem Bityutskiy  * Allow NOMMU mmap() to directly map the device (if not NULL)
14608273a0c9SArtem Bityutskiy  * - return the address to which the offset maps
14618273a0c9SArtem Bityutskiy  * - return -ENOSYS to indicate refusal to do the mapping
14628273a0c9SArtem Bityutskiy  */
mtd_get_unmapped_area(struct mtd_info * mtd,unsigned long len,unsigned long offset,unsigned long flags)14638273a0c9SArtem Bityutskiy unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
14648273a0c9SArtem Bityutskiy 				    unsigned long offset, unsigned long flags)
14658273a0c9SArtem Bityutskiy {
14669eaa903cSNicolas Pitre 	size_t retlen;
14679eaa903cSNicolas Pitre 	void *virt;
14689eaa903cSNicolas Pitre 	int ret;
14699eaa903cSNicolas Pitre 
14709eaa903cSNicolas Pitre 	ret = mtd_point(mtd, offset, len, &retlen, &virt, NULL);
14719eaa903cSNicolas Pitre 	if (ret)
14729eaa903cSNicolas Pitre 		return ret;
14739eaa903cSNicolas Pitre 	if (retlen != len) {
14749eaa903cSNicolas Pitre 		mtd_unpoint(mtd, offset, retlen);
14759eaa903cSNicolas Pitre 		return -ENOSYS;
14769eaa903cSNicolas Pitre 	}
14779eaa903cSNicolas Pitre 	return (unsigned long)virt;
14788273a0c9SArtem Bityutskiy }
14798273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
14808273a0c9SArtem Bityutskiy 
mtd_update_ecc_stats(struct mtd_info * mtd,struct mtd_info * master,const struct mtd_ecc_stats * old_stats)148146b5889cSMiquel Raynal static void mtd_update_ecc_stats(struct mtd_info *mtd, struct mtd_info *master,
148246b5889cSMiquel Raynal 				 const struct mtd_ecc_stats *old_stats)
148346b5889cSMiquel Raynal {
148446b5889cSMiquel Raynal 	struct mtd_ecc_stats diff;
148546b5889cSMiquel Raynal 
148646b5889cSMiquel Raynal 	if (master == mtd)
148746b5889cSMiquel Raynal 		return;
148846b5889cSMiquel Raynal 
148946b5889cSMiquel Raynal 	diff = master->ecc_stats;
149046b5889cSMiquel Raynal 	diff.failed -= old_stats->failed;
149146b5889cSMiquel Raynal 	diff.corrected -= old_stats->corrected;
149246b5889cSMiquel Raynal 
149346b5889cSMiquel Raynal 	while (mtd->parent) {
149446b5889cSMiquel Raynal 		mtd->ecc_stats.failed += diff.failed;
149546b5889cSMiquel Raynal 		mtd->ecc_stats.corrected += diff.corrected;
149646b5889cSMiquel Raynal 		mtd = mtd->parent;
149746b5889cSMiquel Raynal 	}
149846b5889cSMiquel Raynal }
149946b5889cSMiquel Raynal 
mtd_read(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)15008273a0c9SArtem Bityutskiy int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
15018273a0c9SArtem Bityutskiy 	     u_char *buf)
15028273a0c9SArtem Bityutskiy {
150324ff1292SBoris Brezillon 	struct mtd_oob_ops ops = {
150424ff1292SBoris Brezillon 		.len = len,
150524ff1292SBoris Brezillon 		.datbuf = buf,
150624ff1292SBoris Brezillon 	};
15072431c4f5SBoris Brezillon 	int ret;
150824ff1292SBoris Brezillon 
15092431c4f5SBoris Brezillon 	ret = mtd_read_oob(mtd, from, &ops);
151024ff1292SBoris Brezillon 	*retlen = ops.retlen;
151124ff1292SBoris Brezillon 
15122431c4f5SBoris Brezillon 	return ret;
15138273a0c9SArtem Bityutskiy }
15148273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_read);
15158273a0c9SArtem Bityutskiy 
mtd_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)15168273a0c9SArtem Bityutskiy int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
15178273a0c9SArtem Bityutskiy 	      const u_char *buf)
15188273a0c9SArtem Bityutskiy {
151924ff1292SBoris Brezillon 	struct mtd_oob_ops ops = {
152024ff1292SBoris Brezillon 		.len = len,
152124ff1292SBoris Brezillon 		.datbuf = (u8 *)buf,
152224ff1292SBoris Brezillon 	};
152324ff1292SBoris Brezillon 	int ret;
152424ff1292SBoris Brezillon 
15252431c4f5SBoris Brezillon 	ret = mtd_write_oob(mtd, to, &ops);
152624ff1292SBoris Brezillon 	*retlen = ops.retlen;
152724ff1292SBoris Brezillon 
15282431c4f5SBoris Brezillon 	return ret;
15298273a0c9SArtem Bityutskiy }
15308273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_write);
15318273a0c9SArtem Bityutskiy 
15328273a0c9SArtem Bityutskiy /*
15338273a0c9SArtem Bityutskiy  * In blackbox flight recorder like scenarios we want to make successful writes
15348273a0c9SArtem Bityutskiy  * in interrupt context. panic_write() is only intended to be called when its
15358273a0c9SArtem Bityutskiy  * known the kernel is about to panic and we need the write to succeed. Since
15368273a0c9SArtem Bityutskiy  * the kernel is not going to be running for much longer, this function can
15378273a0c9SArtem Bityutskiy  * break locks and delay to ensure the write succeeds (but not sleep).
15388273a0c9SArtem Bityutskiy  */
mtd_panic_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)15398273a0c9SArtem Bityutskiy int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
15408273a0c9SArtem Bityutskiy 		    const u_char *buf)
15418273a0c9SArtem Bityutskiy {
154246b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
154346b5889cSMiquel Raynal 
15448273a0c9SArtem Bityutskiy 	*retlen = 0;
154546b5889cSMiquel Raynal 	if (!master->_panic_write)
15468273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
15470c2b4e21SBrian Norris 	if (to < 0 || to >= mtd->size || len > mtd->size - to)
15488273a0c9SArtem Bityutskiy 		return -EINVAL;
1549664addc2SArtem Bityutskiy 	if (!(mtd->flags & MTD_WRITEABLE))
1550664addc2SArtem Bityutskiy 		return -EROFS;
1551bcb1d238SArtem Bityutskiy 	if (!len)
1552bcb1d238SArtem Bityutskiy 		return 0;
1553630e8d55SKamal Dasu 	if (!master->oops_panic_write)
1554630e8d55SKamal Dasu 		master->oops_panic_write = true;
15559f897bfdSKamal Dasu 
155646b5889cSMiquel Raynal 	return master->_panic_write(master, mtd_get_master_ofs(mtd, to), len,
155746b5889cSMiquel Raynal 				    retlen, buf);
15588273a0c9SArtem Bityutskiy }
15598273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_panic_write);
15608273a0c9SArtem Bityutskiy 
mtd_check_oob_ops(struct mtd_info * mtd,loff_t offs,struct mtd_oob_ops * ops)15615cdd929dSBoris Brezillon static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs,
15625cdd929dSBoris Brezillon 			     struct mtd_oob_ops *ops)
15635cdd929dSBoris Brezillon {
15645cdd929dSBoris Brezillon 	/*
15655cdd929dSBoris Brezillon 	 * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving
15665cdd929dSBoris Brezillon 	 * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in
15675cdd929dSBoris Brezillon 	 *  this case.
15685cdd929dSBoris Brezillon 	 */
15695cdd929dSBoris Brezillon 	if (!ops->datbuf)
15705cdd929dSBoris Brezillon 		ops->len = 0;
15715cdd929dSBoris Brezillon 
15725cdd929dSBoris Brezillon 	if (!ops->oobbuf)
15735cdd929dSBoris Brezillon 		ops->ooblen = 0;
15745cdd929dSBoris Brezillon 
1575d82c3682SMiquel Raynal 	if (offs < 0 || offs + ops->len > mtd->size)
15765cdd929dSBoris Brezillon 		return -EINVAL;
15775cdd929dSBoris Brezillon 
15785cdd929dSBoris Brezillon 	if (ops->ooblen) {
157989f706dbSMiquel Raynal 		size_t maxooblen;
15805cdd929dSBoris Brezillon 
15815cdd929dSBoris Brezillon 		if (ops->ooboffs >= mtd_oobavail(mtd, ops))
15825cdd929dSBoris Brezillon 			return -EINVAL;
15835cdd929dSBoris Brezillon 
158489f706dbSMiquel Raynal 		maxooblen = ((size_t)(mtd_div_by_ws(mtd->size, mtd) -
15855cdd929dSBoris Brezillon 				      mtd_div_by_ws(offs, mtd)) *
15865cdd929dSBoris Brezillon 			     mtd_oobavail(mtd, ops)) - ops->ooboffs;
15875cdd929dSBoris Brezillon 		if (ops->ooblen > maxooblen)
15885cdd929dSBoris Brezillon 			return -EINVAL;
15895cdd929dSBoris Brezillon 	}
15905cdd929dSBoris Brezillon 
15915cdd929dSBoris Brezillon 	return 0;
15925cdd929dSBoris Brezillon }
15935cdd929dSBoris Brezillon 
mtd_read_oob_std(struct mtd_info * mtd,loff_t from,struct mtd_oob_ops * ops)15949e3307a1SBoris Brezillon static int mtd_read_oob_std(struct mtd_info *mtd, loff_t from,
15959e3307a1SBoris Brezillon 			    struct mtd_oob_ops *ops)
15969e3307a1SBoris Brezillon {
15979e3307a1SBoris Brezillon 	struct mtd_info *master = mtd_get_master(mtd);
15989e3307a1SBoris Brezillon 	int ret;
15999e3307a1SBoris Brezillon 
16009e3307a1SBoris Brezillon 	from = mtd_get_master_ofs(mtd, from);
16019e3307a1SBoris Brezillon 	if (master->_read_oob)
16029e3307a1SBoris Brezillon 		ret = master->_read_oob(master, from, ops);
16039e3307a1SBoris Brezillon 	else
16049e3307a1SBoris Brezillon 		ret = master->_read(master, from, ops->len, &ops->retlen,
16059e3307a1SBoris Brezillon 				    ops->datbuf);
16069e3307a1SBoris Brezillon 
16079e3307a1SBoris Brezillon 	return ret;
16089e3307a1SBoris Brezillon }
16099e3307a1SBoris Brezillon 
mtd_write_oob_std(struct mtd_info * mtd,loff_t to,struct mtd_oob_ops * ops)16109e3307a1SBoris Brezillon static int mtd_write_oob_std(struct mtd_info *mtd, loff_t to,
16119e3307a1SBoris Brezillon 			     struct mtd_oob_ops *ops)
16129e3307a1SBoris Brezillon {
16139e3307a1SBoris Brezillon 	struct mtd_info *master = mtd_get_master(mtd);
16149e3307a1SBoris Brezillon 	int ret;
16159e3307a1SBoris Brezillon 
16169e3307a1SBoris Brezillon 	to = mtd_get_master_ofs(mtd, to);
16179e3307a1SBoris Brezillon 	if (master->_write_oob)
16189e3307a1SBoris Brezillon 		ret = master->_write_oob(master, to, ops);
16199e3307a1SBoris Brezillon 	else
16209e3307a1SBoris Brezillon 		ret = master->_write(master, to, ops->len, &ops->retlen,
16219e3307a1SBoris Brezillon 				     ops->datbuf);
16229e3307a1SBoris Brezillon 
16239e3307a1SBoris Brezillon 	return ret;
16249e3307a1SBoris Brezillon }
16259e3307a1SBoris Brezillon 
mtd_io_emulated_slc(struct mtd_info * mtd,loff_t start,bool read,struct mtd_oob_ops * ops)16269e3307a1SBoris Brezillon static int mtd_io_emulated_slc(struct mtd_info *mtd, loff_t start, bool read,
16279e3307a1SBoris Brezillon 			       struct mtd_oob_ops *ops)
16289e3307a1SBoris Brezillon {
16299e3307a1SBoris Brezillon 	struct mtd_info *master = mtd_get_master(mtd);
16309e3307a1SBoris Brezillon 	int ngroups = mtd_pairing_groups(master);
16319e3307a1SBoris Brezillon 	int npairs = mtd_wunit_per_eb(master) / ngroups;
16329e3307a1SBoris Brezillon 	struct mtd_oob_ops adjops = *ops;
16339e3307a1SBoris Brezillon 	unsigned int wunit, oobavail;
16349e3307a1SBoris Brezillon 	struct mtd_pairing_info info;
16359e3307a1SBoris Brezillon 	int max_bitflips = 0;
16369e3307a1SBoris Brezillon 	u32 ebofs, pageofs;
16379e3307a1SBoris Brezillon 	loff_t base, pos;
16389e3307a1SBoris Brezillon 
16399e3307a1SBoris Brezillon 	ebofs = mtd_mod_by_eb(start, mtd);
16409e3307a1SBoris Brezillon 	base = (loff_t)mtd_div_by_eb(start, mtd) * master->erasesize;
16419e3307a1SBoris Brezillon 	info.group = 0;
16429e3307a1SBoris Brezillon 	info.pair = mtd_div_by_ws(ebofs, mtd);
16439e3307a1SBoris Brezillon 	pageofs = mtd_mod_by_ws(ebofs, mtd);
16449e3307a1SBoris Brezillon 	oobavail = mtd_oobavail(mtd, ops);
16459e3307a1SBoris Brezillon 
16469e3307a1SBoris Brezillon 	while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) {
16479e3307a1SBoris Brezillon 		int ret;
16489e3307a1SBoris Brezillon 
16499e3307a1SBoris Brezillon 		if (info.pair >= npairs) {
16509e3307a1SBoris Brezillon 			info.pair = 0;
16519e3307a1SBoris Brezillon 			base += master->erasesize;
16529e3307a1SBoris Brezillon 		}
16539e3307a1SBoris Brezillon 
16549e3307a1SBoris Brezillon 		wunit = mtd_pairing_info_to_wunit(master, &info);
16559e3307a1SBoris Brezillon 		pos = mtd_wunit_to_offset(mtd, base, wunit);
16569e3307a1SBoris Brezillon 
16579e3307a1SBoris Brezillon 		adjops.len = ops->len - ops->retlen;
16589e3307a1SBoris Brezillon 		if (adjops.len > mtd->writesize - pageofs)
16599e3307a1SBoris Brezillon 			adjops.len = mtd->writesize - pageofs;
16609e3307a1SBoris Brezillon 
16619e3307a1SBoris Brezillon 		adjops.ooblen = ops->ooblen - ops->oobretlen;
16629e3307a1SBoris Brezillon 		if (adjops.ooblen > oobavail - adjops.ooboffs)
16639e3307a1SBoris Brezillon 			adjops.ooblen = oobavail - adjops.ooboffs;
16649e3307a1SBoris Brezillon 
16659e3307a1SBoris Brezillon 		if (read) {
16669e3307a1SBoris Brezillon 			ret = mtd_read_oob_std(mtd, pos + pageofs, &adjops);
16679e3307a1SBoris Brezillon 			if (ret > 0)
16689e3307a1SBoris Brezillon 				max_bitflips = max(max_bitflips, ret);
16699e3307a1SBoris Brezillon 		} else {
16709e3307a1SBoris Brezillon 			ret = mtd_write_oob_std(mtd, pos + pageofs, &adjops);
16719e3307a1SBoris Brezillon 		}
16729e3307a1SBoris Brezillon 
16739e3307a1SBoris Brezillon 		if (ret < 0)
16749e3307a1SBoris Brezillon 			return ret;
16759e3307a1SBoris Brezillon 
16769e3307a1SBoris Brezillon 		max_bitflips = max(max_bitflips, ret);
16779e3307a1SBoris Brezillon 		ops->retlen += adjops.retlen;
16789e3307a1SBoris Brezillon 		ops->oobretlen += adjops.oobretlen;
16799e3307a1SBoris Brezillon 		adjops.datbuf += adjops.retlen;
16809e3307a1SBoris Brezillon 		adjops.oobbuf += adjops.oobretlen;
16819e3307a1SBoris Brezillon 		adjops.ooboffs = 0;
16829e3307a1SBoris Brezillon 		pageofs = 0;
16839e3307a1SBoris Brezillon 		info.pair++;
16849e3307a1SBoris Brezillon 	}
16859e3307a1SBoris Brezillon 
16869e3307a1SBoris Brezillon 	return max_bitflips;
16879e3307a1SBoris Brezillon }
16889e3307a1SBoris Brezillon 
mtd_read_oob(struct mtd_info * mtd,loff_t from,struct mtd_oob_ops * ops)1689d2d48480SBrian Norris int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
1690d2d48480SBrian Norris {
169146b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
169246b5889cSMiquel Raynal 	struct mtd_ecc_stats old_stats = master->ecc_stats;
1693e47f6858SBrian Norris 	int ret_code;
169446b5889cSMiquel Raynal 
1695d2d48480SBrian Norris 	ops->retlen = ops->oobretlen = 0;
1696fea728c0SEzequiel Garcia 
16975cdd929dSBoris Brezillon 	ret_code = mtd_check_oob_ops(mtd, from, ops);
16985cdd929dSBoris Brezillon 	if (ret_code)
16995cdd929dSBoris Brezillon 		return ret_code;
17005cdd929dSBoris Brezillon 
1701fea728c0SEzequiel Garcia 	ledtrig_mtd_activity();
170289fd23efSMiquel Raynal 
170389fd23efSMiquel Raynal 	/* Check the validity of a potential fallback on mtd->_read */
170446b5889cSMiquel Raynal 	if (!master->_read_oob && (!master->_read || ops->oobbuf))
170589fd23efSMiquel Raynal 		return -EOPNOTSUPP;
170689fd23efSMiquel Raynal 
170765394169SMichał Kępień 	if (ops->stats)
170865394169SMichał Kępień 		memset(ops->stats, 0, sizeof(*ops->stats));
170965394169SMichał Kępień 
17109e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
17119e3307a1SBoris Brezillon 		ret_code = mtd_io_emulated_slc(mtd, from, true, ops);
171289fd23efSMiquel Raynal 	else
17139e3307a1SBoris Brezillon 		ret_code = mtd_read_oob_std(mtd, from, ops);
171489fd23efSMiquel Raynal 
171546b5889cSMiquel Raynal 	mtd_update_ecc_stats(mtd, master, &old_stats);
171646b5889cSMiquel Raynal 
1717e47f6858SBrian Norris 	/*
1718e47f6858SBrian Norris 	 * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
1719e47f6858SBrian Norris 	 * similar to mtd->_read(), returning a non-negative integer
1720e47f6858SBrian Norris 	 * representing max bitflips. In other cases, mtd->_read_oob() may
1721e47f6858SBrian Norris 	 * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
1722e47f6858SBrian Norris 	 */
1723e47f6858SBrian Norris 	if (unlikely(ret_code < 0))
1724e47f6858SBrian Norris 		return ret_code;
1725e47f6858SBrian Norris 	if (mtd->ecc_strength == 0)
1726e47f6858SBrian Norris 		return 0;	/* device lacks ecc */
172765394169SMichał Kępień 	if (ops->stats)
172865394169SMichał Kępień 		ops->stats->max_bitflips = ret_code;
1729e47f6858SBrian Norris 	return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
1730d2d48480SBrian Norris }
1731d2d48480SBrian Norris EXPORT_SYMBOL_GPL(mtd_read_oob);
1732d2d48480SBrian Norris 
mtd_write_oob(struct mtd_info * mtd,loff_t to,struct mtd_oob_ops * ops)17330c034fe3SEzequiel Garcia int mtd_write_oob(struct mtd_info *mtd, loff_t to,
17340c034fe3SEzequiel Garcia 				struct mtd_oob_ops *ops)
17350c034fe3SEzequiel Garcia {
173646b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
17375cdd929dSBoris Brezillon 	int ret;
17385cdd929dSBoris Brezillon 
17390c034fe3SEzequiel Garcia 	ops->retlen = ops->oobretlen = 0;
174089fd23efSMiquel Raynal 
17410c034fe3SEzequiel Garcia 	if (!(mtd->flags & MTD_WRITEABLE))
17420c034fe3SEzequiel Garcia 		return -EROFS;
17435cdd929dSBoris Brezillon 
17445cdd929dSBoris Brezillon 	ret = mtd_check_oob_ops(mtd, to, ops);
17455cdd929dSBoris Brezillon 	if (ret)
17465cdd929dSBoris Brezillon 		return ret;
17475cdd929dSBoris Brezillon 
1748fea728c0SEzequiel Garcia 	ledtrig_mtd_activity();
174989fd23efSMiquel Raynal 
175089fd23efSMiquel Raynal 	/* Check the validity of a potential fallback on mtd->_write */
175146b5889cSMiquel Raynal 	if (!master->_write_oob && (!master->_write || ops->oobbuf))
175289fd23efSMiquel Raynal 		return -EOPNOTSUPP;
175389fd23efSMiquel Raynal 
17549e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
17559e3307a1SBoris Brezillon 		return mtd_io_emulated_slc(mtd, to, false, ops);
175646b5889cSMiquel Raynal 
17579e3307a1SBoris Brezillon 	return mtd_write_oob_std(mtd, to, ops);
17580c034fe3SEzequiel Garcia }
17590c034fe3SEzequiel Garcia EXPORT_SYMBOL_GPL(mtd_write_oob);
17600c034fe3SEzequiel Garcia 
176175eb2cecSBoris Brezillon /**
176275eb2cecSBoris Brezillon  * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
176375eb2cecSBoris Brezillon  * @mtd: MTD device structure
176475eb2cecSBoris Brezillon  * @section: ECC section. Depending on the layout you may have all the ECC
176575eb2cecSBoris Brezillon  *	     bytes stored in a single contiguous section, or one section
176675eb2cecSBoris Brezillon  *	     per ECC chunk (and sometime several sections for a single ECC
176775eb2cecSBoris Brezillon  *	     ECC chunk)
176875eb2cecSBoris Brezillon  * @oobecc: OOB region struct filled with the appropriate ECC position
176975eb2cecSBoris Brezillon  *	    information
177075eb2cecSBoris Brezillon  *
17717da0fffbSMasahiro Yamada  * This function returns ECC section information in the OOB area. If you want
177275eb2cecSBoris Brezillon  * to get all the ECC bytes information, then you should call
177375eb2cecSBoris Brezillon  * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
177475eb2cecSBoris Brezillon  *
177575eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
177675eb2cecSBoris Brezillon  */
mtd_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobecc)177775eb2cecSBoris Brezillon int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
177875eb2cecSBoris Brezillon 		      struct mtd_oob_region *oobecc)
177975eb2cecSBoris Brezillon {
178046b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
178146b5889cSMiquel Raynal 
178275eb2cecSBoris Brezillon 	memset(oobecc, 0, sizeof(*oobecc));
178375eb2cecSBoris Brezillon 
178446b5889cSMiquel Raynal 	if (!master || section < 0)
178575eb2cecSBoris Brezillon 		return -EINVAL;
178675eb2cecSBoris Brezillon 
178746b5889cSMiquel Raynal 	if (!master->ooblayout || !master->ooblayout->ecc)
178875eb2cecSBoris Brezillon 		return -ENOTSUPP;
178975eb2cecSBoris Brezillon 
179046b5889cSMiquel Raynal 	return master->ooblayout->ecc(master, section, oobecc);
179175eb2cecSBoris Brezillon }
179275eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
179375eb2cecSBoris Brezillon 
179475eb2cecSBoris Brezillon /**
179575eb2cecSBoris Brezillon  * mtd_ooblayout_free - Get the OOB region definition of a specific free
179675eb2cecSBoris Brezillon  *			section
179775eb2cecSBoris Brezillon  * @mtd: MTD device structure
179875eb2cecSBoris Brezillon  * @section: Free section you are interested in. Depending on the layout
179975eb2cecSBoris Brezillon  *	     you may have all the free bytes stored in a single contiguous
180075eb2cecSBoris Brezillon  *	     section, or one section per ECC chunk plus an extra section
180175eb2cecSBoris Brezillon  *	     for the remaining bytes (or other funky layout).
180275eb2cecSBoris Brezillon  * @oobfree: OOB region struct filled with the appropriate free position
180375eb2cecSBoris Brezillon  *	     information
180475eb2cecSBoris Brezillon  *
18057da0fffbSMasahiro Yamada  * This function returns free bytes position in the OOB area. If you want
180675eb2cecSBoris Brezillon  * to get all the free bytes information, then you should call
180775eb2cecSBoris Brezillon  * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
180875eb2cecSBoris Brezillon  *
180975eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
181075eb2cecSBoris Brezillon  */
mtd_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobfree)181175eb2cecSBoris Brezillon int mtd_ooblayout_free(struct mtd_info *mtd, int section,
181275eb2cecSBoris Brezillon 		       struct mtd_oob_region *oobfree)
181375eb2cecSBoris Brezillon {
181446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
181546b5889cSMiquel Raynal 
181675eb2cecSBoris Brezillon 	memset(oobfree, 0, sizeof(*oobfree));
181775eb2cecSBoris Brezillon 
181846b5889cSMiquel Raynal 	if (!master || section < 0)
181975eb2cecSBoris Brezillon 		return -EINVAL;
182075eb2cecSBoris Brezillon 
182146b5889cSMiquel Raynal 	if (!master->ooblayout || !master->ooblayout->free)
182275eb2cecSBoris Brezillon 		return -ENOTSUPP;
182375eb2cecSBoris Brezillon 
182446b5889cSMiquel Raynal 	return master->ooblayout->free(master, section, oobfree);
182575eb2cecSBoris Brezillon }
182675eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
182775eb2cecSBoris Brezillon 
182875eb2cecSBoris Brezillon /**
182975eb2cecSBoris Brezillon  * mtd_ooblayout_find_region - Find the region attached to a specific byte
183075eb2cecSBoris Brezillon  * @mtd: mtd info structure
183175eb2cecSBoris Brezillon  * @byte: the byte we are searching for
183275eb2cecSBoris Brezillon  * @sectionp: pointer where the section id will be stored
183375eb2cecSBoris Brezillon  * @oobregion: used to retrieve the ECC position
183475eb2cecSBoris Brezillon  * @iter: iterator function. Should be either mtd_ooblayout_free or
183575eb2cecSBoris Brezillon  *	  mtd_ooblayout_ecc depending on the region type you're searching for
183675eb2cecSBoris Brezillon  *
18377da0fffbSMasahiro Yamada  * This function returns the section id and oobregion information of a
183875eb2cecSBoris Brezillon  * specific byte. For example, say you want to know where the 4th ECC byte is
183975eb2cecSBoris Brezillon  * stored, you'll use:
184075eb2cecSBoris Brezillon  *
184175eb2cecSBoris Brezillon  * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
184275eb2cecSBoris Brezillon  *
184375eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
184475eb2cecSBoris Brezillon  */
mtd_ooblayout_find_region(struct mtd_info * mtd,int byte,int * sectionp,struct mtd_oob_region * oobregion,int (* iter)(struct mtd_info *,int section,struct mtd_oob_region * oobregion))184575eb2cecSBoris Brezillon static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
184675eb2cecSBoris Brezillon 				int *sectionp, struct mtd_oob_region *oobregion,
184775eb2cecSBoris Brezillon 				int (*iter)(struct mtd_info *,
184875eb2cecSBoris Brezillon 					    int section,
184975eb2cecSBoris Brezillon 					    struct mtd_oob_region *oobregion))
185075eb2cecSBoris Brezillon {
185175eb2cecSBoris Brezillon 	int pos = 0, ret, section = 0;
185275eb2cecSBoris Brezillon 
185375eb2cecSBoris Brezillon 	memset(oobregion, 0, sizeof(*oobregion));
185475eb2cecSBoris Brezillon 
185575eb2cecSBoris Brezillon 	while (1) {
185675eb2cecSBoris Brezillon 		ret = iter(mtd, section, oobregion);
185775eb2cecSBoris Brezillon 		if (ret)
185875eb2cecSBoris Brezillon 			return ret;
185975eb2cecSBoris Brezillon 
186075eb2cecSBoris Brezillon 		if (pos + oobregion->length > byte)
186175eb2cecSBoris Brezillon 			break;
186275eb2cecSBoris Brezillon 
186375eb2cecSBoris Brezillon 		pos += oobregion->length;
186475eb2cecSBoris Brezillon 		section++;
186575eb2cecSBoris Brezillon 	}
186675eb2cecSBoris Brezillon 
186775eb2cecSBoris Brezillon 	/*
186875eb2cecSBoris Brezillon 	 * Adjust region info to make it start at the beginning at the
186975eb2cecSBoris Brezillon 	 * 'start' ECC byte.
187075eb2cecSBoris Brezillon 	 */
187175eb2cecSBoris Brezillon 	oobregion->offset += byte - pos;
187275eb2cecSBoris Brezillon 	oobregion->length -= byte - pos;
187375eb2cecSBoris Brezillon 	*sectionp = section;
187475eb2cecSBoris Brezillon 
187575eb2cecSBoris Brezillon 	return 0;
187675eb2cecSBoris Brezillon }
187775eb2cecSBoris Brezillon 
187875eb2cecSBoris Brezillon /**
187975eb2cecSBoris Brezillon  * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
188075eb2cecSBoris Brezillon  *				  ECC byte
188175eb2cecSBoris Brezillon  * @mtd: mtd info structure
188275eb2cecSBoris Brezillon  * @eccbyte: the byte we are searching for
18836361f536SLee Jones  * @section: pointer where the section id will be stored
188475eb2cecSBoris Brezillon  * @oobregion: OOB region information
188575eb2cecSBoris Brezillon  *
188675eb2cecSBoris Brezillon  * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
188775eb2cecSBoris Brezillon  * byte.
188875eb2cecSBoris Brezillon  *
188975eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
189075eb2cecSBoris Brezillon  */
mtd_ooblayout_find_eccregion(struct mtd_info * mtd,int eccbyte,int * section,struct mtd_oob_region * oobregion)189175eb2cecSBoris Brezillon int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
189275eb2cecSBoris Brezillon 				 int *section,
189375eb2cecSBoris Brezillon 				 struct mtd_oob_region *oobregion)
189475eb2cecSBoris Brezillon {
189575eb2cecSBoris Brezillon 	return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
189675eb2cecSBoris Brezillon 					 mtd_ooblayout_ecc);
189775eb2cecSBoris Brezillon }
189875eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
189975eb2cecSBoris Brezillon 
190075eb2cecSBoris Brezillon /**
190175eb2cecSBoris Brezillon  * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
190275eb2cecSBoris Brezillon  * @mtd: mtd info structure
190375eb2cecSBoris Brezillon  * @buf: destination buffer to store OOB bytes
190475eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
190575eb2cecSBoris Brezillon  * @start: first byte to retrieve
190675eb2cecSBoris Brezillon  * @nbytes: number of bytes to retrieve
190775eb2cecSBoris Brezillon  * @iter: section iterator
190875eb2cecSBoris Brezillon  *
190975eb2cecSBoris Brezillon  * Extract bytes attached to a specific category (ECC or free)
191075eb2cecSBoris Brezillon  * from the OOB buffer and copy them into buf.
191175eb2cecSBoris Brezillon  *
191275eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
191375eb2cecSBoris Brezillon  */
mtd_ooblayout_get_bytes(struct mtd_info * mtd,u8 * buf,const u8 * oobbuf,int start,int nbytes,int (* iter)(struct mtd_info *,int section,struct mtd_oob_region * oobregion))191475eb2cecSBoris Brezillon static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
191575eb2cecSBoris Brezillon 				const u8 *oobbuf, int start, int nbytes,
191675eb2cecSBoris Brezillon 				int (*iter)(struct mtd_info *,
191775eb2cecSBoris Brezillon 					    int section,
191875eb2cecSBoris Brezillon 					    struct mtd_oob_region *oobregion))
191975eb2cecSBoris Brezillon {
19208e8fd4d1SMasahiro Yamada 	struct mtd_oob_region oobregion;
19218e8fd4d1SMasahiro Yamada 	int section, ret;
192275eb2cecSBoris Brezillon 
192375eb2cecSBoris Brezillon 	ret = mtd_ooblayout_find_region(mtd, start, &section,
192475eb2cecSBoris Brezillon 					&oobregion, iter);
192575eb2cecSBoris Brezillon 
192675eb2cecSBoris Brezillon 	while (!ret) {
192775eb2cecSBoris Brezillon 		int cnt;
192875eb2cecSBoris Brezillon 
19297c295ef9SMasahiro Yamada 		cnt = min_t(int, nbytes, oobregion.length);
193075eb2cecSBoris Brezillon 		memcpy(buf, oobbuf + oobregion.offset, cnt);
193175eb2cecSBoris Brezillon 		buf += cnt;
193275eb2cecSBoris Brezillon 		nbytes -= cnt;
193375eb2cecSBoris Brezillon 
193475eb2cecSBoris Brezillon 		if (!nbytes)
193575eb2cecSBoris Brezillon 			break;
193675eb2cecSBoris Brezillon 
193775eb2cecSBoris Brezillon 		ret = iter(mtd, ++section, &oobregion);
193875eb2cecSBoris Brezillon 	}
193975eb2cecSBoris Brezillon 
194075eb2cecSBoris Brezillon 	return ret;
194175eb2cecSBoris Brezillon }
194275eb2cecSBoris Brezillon 
194375eb2cecSBoris Brezillon /**
194475eb2cecSBoris Brezillon  * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
194575eb2cecSBoris Brezillon  * @mtd: mtd info structure
194675eb2cecSBoris Brezillon  * @buf: source buffer to get OOB bytes from
194775eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
194875eb2cecSBoris Brezillon  * @start: first OOB byte to set
194975eb2cecSBoris Brezillon  * @nbytes: number of OOB bytes to set
195075eb2cecSBoris Brezillon  * @iter: section iterator
195175eb2cecSBoris Brezillon  *
195275eb2cecSBoris Brezillon  * Fill the OOB buffer with data provided in buf. The category (ECC or free)
195375eb2cecSBoris Brezillon  * is selected by passing the appropriate iterator.
195475eb2cecSBoris Brezillon  *
195575eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
195675eb2cecSBoris Brezillon  */
mtd_ooblayout_set_bytes(struct mtd_info * mtd,const u8 * buf,u8 * oobbuf,int start,int nbytes,int (* iter)(struct mtd_info *,int section,struct mtd_oob_region * oobregion))195775eb2cecSBoris Brezillon static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
195875eb2cecSBoris Brezillon 				u8 *oobbuf, int start, int nbytes,
195975eb2cecSBoris Brezillon 				int (*iter)(struct mtd_info *,
196075eb2cecSBoris Brezillon 					    int section,
196175eb2cecSBoris Brezillon 					    struct mtd_oob_region *oobregion))
196275eb2cecSBoris Brezillon {
19638e8fd4d1SMasahiro Yamada 	struct mtd_oob_region oobregion;
19648e8fd4d1SMasahiro Yamada 	int section, ret;
196575eb2cecSBoris Brezillon 
196675eb2cecSBoris Brezillon 	ret = mtd_ooblayout_find_region(mtd, start, &section,
196775eb2cecSBoris Brezillon 					&oobregion, iter);
196875eb2cecSBoris Brezillon 
196975eb2cecSBoris Brezillon 	while (!ret) {
197075eb2cecSBoris Brezillon 		int cnt;
197175eb2cecSBoris Brezillon 
19727c295ef9SMasahiro Yamada 		cnt = min_t(int, nbytes, oobregion.length);
197375eb2cecSBoris Brezillon 		memcpy(oobbuf + oobregion.offset, buf, cnt);
197475eb2cecSBoris Brezillon 		buf += cnt;
197575eb2cecSBoris Brezillon 		nbytes -= cnt;
197675eb2cecSBoris Brezillon 
197775eb2cecSBoris Brezillon 		if (!nbytes)
197875eb2cecSBoris Brezillon 			break;
197975eb2cecSBoris Brezillon 
198075eb2cecSBoris Brezillon 		ret = iter(mtd, ++section, &oobregion);
198175eb2cecSBoris Brezillon 	}
198275eb2cecSBoris Brezillon 
198375eb2cecSBoris Brezillon 	return ret;
198475eb2cecSBoris Brezillon }
198575eb2cecSBoris Brezillon 
198675eb2cecSBoris Brezillon /**
198775eb2cecSBoris Brezillon  * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
198875eb2cecSBoris Brezillon  * @mtd: mtd info structure
198975eb2cecSBoris Brezillon  * @iter: category iterator
199075eb2cecSBoris Brezillon  *
199175eb2cecSBoris Brezillon  * Count the number of bytes in a given category.
199275eb2cecSBoris Brezillon  *
199375eb2cecSBoris Brezillon  * Returns a positive value on success, a negative error code otherwise.
199475eb2cecSBoris Brezillon  */
mtd_ooblayout_count_bytes(struct mtd_info * mtd,int (* iter)(struct mtd_info *,int section,struct mtd_oob_region * oobregion))199575eb2cecSBoris Brezillon static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
199675eb2cecSBoris Brezillon 				int (*iter)(struct mtd_info *,
199775eb2cecSBoris Brezillon 					    int section,
199875eb2cecSBoris Brezillon 					    struct mtd_oob_region *oobregion))
199975eb2cecSBoris Brezillon {
20004d6aecfbSMasahiro Yamada 	struct mtd_oob_region oobregion;
200175eb2cecSBoris Brezillon 	int section = 0, ret, nbytes = 0;
200275eb2cecSBoris Brezillon 
200375eb2cecSBoris Brezillon 	while (1) {
200475eb2cecSBoris Brezillon 		ret = iter(mtd, section++, &oobregion);
200575eb2cecSBoris Brezillon 		if (ret) {
200675eb2cecSBoris Brezillon 			if (ret == -ERANGE)
200775eb2cecSBoris Brezillon 				ret = nbytes;
200875eb2cecSBoris Brezillon 			break;
200975eb2cecSBoris Brezillon 		}
201075eb2cecSBoris Brezillon 
201175eb2cecSBoris Brezillon 		nbytes += oobregion.length;
201275eb2cecSBoris Brezillon 	}
201375eb2cecSBoris Brezillon 
201475eb2cecSBoris Brezillon 	return ret;
201575eb2cecSBoris Brezillon }
201675eb2cecSBoris Brezillon 
201775eb2cecSBoris Brezillon /**
201875eb2cecSBoris Brezillon  * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
201975eb2cecSBoris Brezillon  * @mtd: mtd info structure
202075eb2cecSBoris Brezillon  * @eccbuf: destination buffer to store ECC bytes
202175eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
202275eb2cecSBoris Brezillon  * @start: first ECC byte to retrieve
202375eb2cecSBoris Brezillon  * @nbytes: number of ECC bytes to retrieve
202475eb2cecSBoris Brezillon  *
202575eb2cecSBoris Brezillon  * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
202675eb2cecSBoris Brezillon  *
202775eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
202875eb2cecSBoris Brezillon  */
mtd_ooblayout_get_eccbytes(struct mtd_info * mtd,u8 * eccbuf,const u8 * oobbuf,int start,int nbytes)202975eb2cecSBoris Brezillon int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
203075eb2cecSBoris Brezillon 			       const u8 *oobbuf, int start, int nbytes)
203175eb2cecSBoris Brezillon {
203275eb2cecSBoris Brezillon 	return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
203375eb2cecSBoris Brezillon 				       mtd_ooblayout_ecc);
203475eb2cecSBoris Brezillon }
203575eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
203675eb2cecSBoris Brezillon 
203775eb2cecSBoris Brezillon /**
203875eb2cecSBoris Brezillon  * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
203975eb2cecSBoris Brezillon  * @mtd: mtd info structure
204075eb2cecSBoris Brezillon  * @eccbuf: source buffer to get ECC bytes from
204175eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
204275eb2cecSBoris Brezillon  * @start: first ECC byte to set
204375eb2cecSBoris Brezillon  * @nbytes: number of ECC bytes to set
204475eb2cecSBoris Brezillon  *
204575eb2cecSBoris Brezillon  * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
204675eb2cecSBoris Brezillon  *
204775eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
204875eb2cecSBoris Brezillon  */
mtd_ooblayout_set_eccbytes(struct mtd_info * mtd,const u8 * eccbuf,u8 * oobbuf,int start,int nbytes)204975eb2cecSBoris Brezillon int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
205075eb2cecSBoris Brezillon 			       u8 *oobbuf, int start, int nbytes)
205175eb2cecSBoris Brezillon {
205275eb2cecSBoris Brezillon 	return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
205375eb2cecSBoris Brezillon 				       mtd_ooblayout_ecc);
205475eb2cecSBoris Brezillon }
205575eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
205675eb2cecSBoris Brezillon 
205775eb2cecSBoris Brezillon /**
205875eb2cecSBoris Brezillon  * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
205975eb2cecSBoris Brezillon  * @mtd: mtd info structure
206075eb2cecSBoris Brezillon  * @databuf: destination buffer to store ECC bytes
206175eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
206275eb2cecSBoris Brezillon  * @start: first ECC byte to retrieve
206375eb2cecSBoris Brezillon  * @nbytes: number of ECC bytes to retrieve
206475eb2cecSBoris Brezillon  *
206575eb2cecSBoris Brezillon  * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
206675eb2cecSBoris Brezillon  *
206775eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
206875eb2cecSBoris Brezillon  */
mtd_ooblayout_get_databytes(struct mtd_info * mtd,u8 * databuf,const u8 * oobbuf,int start,int nbytes)206975eb2cecSBoris Brezillon int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
207075eb2cecSBoris Brezillon 				const u8 *oobbuf, int start, int nbytes)
207175eb2cecSBoris Brezillon {
207275eb2cecSBoris Brezillon 	return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
207375eb2cecSBoris Brezillon 				       mtd_ooblayout_free);
207475eb2cecSBoris Brezillon }
207575eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
207675eb2cecSBoris Brezillon 
207775eb2cecSBoris Brezillon /**
2078c77a9312SXiaolei Li  * mtd_ooblayout_set_databytes - set data bytes into the oob buffer
207975eb2cecSBoris Brezillon  * @mtd: mtd info structure
2080c77a9312SXiaolei Li  * @databuf: source buffer to get data bytes from
208175eb2cecSBoris Brezillon  * @oobbuf: OOB buffer
208275eb2cecSBoris Brezillon  * @start: first ECC byte to set
208375eb2cecSBoris Brezillon  * @nbytes: number of ECC bytes to set
208475eb2cecSBoris Brezillon  *
2085519494a9SMiquel Raynal  * Works like mtd_ooblayout_set_bytes(), except it acts on free bytes.
208675eb2cecSBoris Brezillon  *
208775eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
208875eb2cecSBoris Brezillon  */
mtd_ooblayout_set_databytes(struct mtd_info * mtd,const u8 * databuf,u8 * oobbuf,int start,int nbytes)208975eb2cecSBoris Brezillon int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
209075eb2cecSBoris Brezillon 				u8 *oobbuf, int start, int nbytes)
209175eb2cecSBoris Brezillon {
209275eb2cecSBoris Brezillon 	return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
209375eb2cecSBoris Brezillon 				       mtd_ooblayout_free);
209475eb2cecSBoris Brezillon }
209575eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
209675eb2cecSBoris Brezillon 
209775eb2cecSBoris Brezillon /**
209875eb2cecSBoris Brezillon  * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
209975eb2cecSBoris Brezillon  * @mtd: mtd info structure
210075eb2cecSBoris Brezillon  *
210175eb2cecSBoris Brezillon  * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
210275eb2cecSBoris Brezillon  *
210375eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
210475eb2cecSBoris Brezillon  */
mtd_ooblayout_count_freebytes(struct mtd_info * mtd)210575eb2cecSBoris Brezillon int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
210675eb2cecSBoris Brezillon {
210775eb2cecSBoris Brezillon 	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
210875eb2cecSBoris Brezillon }
210975eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
211075eb2cecSBoris Brezillon 
211175eb2cecSBoris Brezillon /**
2112c77a9312SXiaolei Li  * mtd_ooblayout_count_eccbytes - count the number of ECC bytes in OOB
211375eb2cecSBoris Brezillon  * @mtd: mtd info structure
211475eb2cecSBoris Brezillon  *
211575eb2cecSBoris Brezillon  * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
211675eb2cecSBoris Brezillon  *
211775eb2cecSBoris Brezillon  * Returns zero on success, a negative error code otherwise.
211875eb2cecSBoris Brezillon  */
mtd_ooblayout_count_eccbytes(struct mtd_info * mtd)211975eb2cecSBoris Brezillon int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
212075eb2cecSBoris Brezillon {
212175eb2cecSBoris Brezillon 	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
212275eb2cecSBoris Brezillon }
212375eb2cecSBoris Brezillon EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
212475eb2cecSBoris Brezillon 
2125de3cac93SArtem Bityutskiy /*
2126de3cac93SArtem Bityutskiy  * Method to access the protection register area, present in some flash
2127de3cac93SArtem Bityutskiy  * devices. The user data is one time programmable but the factory data is read
2128de3cac93SArtem Bityutskiy  * only.
2129de3cac93SArtem Bityutskiy  */
mtd_get_fact_prot_info(struct mtd_info * mtd,size_t len,size_t * retlen,struct otp_info * buf)21304b78fc42SChristian Riesch int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
21314b78fc42SChristian Riesch 			   struct otp_info *buf)
2132de3cac93SArtem Bityutskiy {
213346b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
213446b5889cSMiquel Raynal 
213546b5889cSMiquel Raynal 	if (!master->_get_fact_prot_info)
2136de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2137de3cac93SArtem Bityutskiy 	if (!len)
2138de3cac93SArtem Bityutskiy 		return 0;
213946b5889cSMiquel Raynal 	return master->_get_fact_prot_info(master, len, retlen, buf);
2140de3cac93SArtem Bityutskiy }
2141de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
2142de3cac93SArtem Bityutskiy 
mtd_read_fact_prot_reg(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)2143de3cac93SArtem Bityutskiy int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
2144de3cac93SArtem Bityutskiy 			   size_t *retlen, u_char *buf)
2145de3cac93SArtem Bityutskiy {
214646b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
214746b5889cSMiquel Raynal 
2148de3cac93SArtem Bityutskiy 	*retlen = 0;
214946b5889cSMiquel Raynal 	if (!master->_read_fact_prot_reg)
2150de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2151de3cac93SArtem Bityutskiy 	if (!len)
2152de3cac93SArtem Bityutskiy 		return 0;
215346b5889cSMiquel Raynal 	return master->_read_fact_prot_reg(master, from, len, retlen, buf);
2154de3cac93SArtem Bityutskiy }
2155de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
2156de3cac93SArtem Bityutskiy 
mtd_get_user_prot_info(struct mtd_info * mtd,size_t len,size_t * retlen,struct otp_info * buf)21574b78fc42SChristian Riesch int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
21584b78fc42SChristian Riesch 			   struct otp_info *buf)
2159de3cac93SArtem Bityutskiy {
216046b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
216146b5889cSMiquel Raynal 
216246b5889cSMiquel Raynal 	if (!master->_get_user_prot_info)
2163de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2164de3cac93SArtem Bityutskiy 	if (!len)
2165de3cac93SArtem Bityutskiy 		return 0;
216646b5889cSMiquel Raynal 	return master->_get_user_prot_info(master, len, retlen, buf);
2167de3cac93SArtem Bityutskiy }
2168de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
2169de3cac93SArtem Bityutskiy 
mtd_read_user_prot_reg(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)2170de3cac93SArtem Bityutskiy int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
2171de3cac93SArtem Bityutskiy 			   size_t *retlen, u_char *buf)
2172de3cac93SArtem Bityutskiy {
217346b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
217446b5889cSMiquel Raynal 
2175de3cac93SArtem Bityutskiy 	*retlen = 0;
217646b5889cSMiquel Raynal 	if (!master->_read_user_prot_reg)
2177de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2178de3cac93SArtem Bityutskiy 	if (!len)
2179de3cac93SArtem Bityutskiy 		return 0;
218046b5889cSMiquel Raynal 	return master->_read_user_prot_reg(master, from, len, retlen, buf);
2181de3cac93SArtem Bityutskiy }
2182de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
2183de3cac93SArtem Bityutskiy 
mtd_write_user_prot_reg(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)2184de3cac93SArtem Bityutskiy int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
21851df1fc8cSTudor Ambarus 			    size_t *retlen, const u_char *buf)
2186de3cac93SArtem Bityutskiy {
218746b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
21889a78bc83SChristian Riesch 	int ret;
21899a78bc83SChristian Riesch 
2190de3cac93SArtem Bityutskiy 	*retlen = 0;
219146b5889cSMiquel Raynal 	if (!master->_write_user_prot_reg)
2192de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2193de3cac93SArtem Bityutskiy 	if (!len)
2194de3cac93SArtem Bityutskiy 		return 0;
219546b5889cSMiquel Raynal 	ret = master->_write_user_prot_reg(master, to, len, retlen, buf);
21969a78bc83SChristian Riesch 	if (ret)
21979a78bc83SChristian Riesch 		return ret;
21989a78bc83SChristian Riesch 
21999a78bc83SChristian Riesch 	/*
22009a78bc83SChristian Riesch 	 * If no data could be written at all, we are out of memory and
22019a78bc83SChristian Riesch 	 * must return -ENOSPC.
22029a78bc83SChristian Riesch 	 */
22039a78bc83SChristian Riesch 	return (*retlen) ? 0 : -ENOSPC;
2204de3cac93SArtem Bityutskiy }
2205de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
2206de3cac93SArtem Bityutskiy 
mtd_lock_user_prot_reg(struct mtd_info * mtd,loff_t from,size_t len)2207de3cac93SArtem Bityutskiy int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
2208de3cac93SArtem Bityutskiy {
220946b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
221046b5889cSMiquel Raynal 
221146b5889cSMiquel Raynal 	if (!master->_lock_user_prot_reg)
2212de3cac93SArtem Bityutskiy 		return -EOPNOTSUPP;
2213de3cac93SArtem Bityutskiy 	if (!len)
2214de3cac93SArtem Bityutskiy 		return 0;
221546b5889cSMiquel Raynal 	return master->_lock_user_prot_reg(master, from, len);
2216de3cac93SArtem Bityutskiy }
2217de3cac93SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
2218de3cac93SArtem Bityutskiy 
mtd_erase_user_prot_reg(struct mtd_info * mtd,loff_t from,size_t len)2219e3c1f1c9SMichael Walle int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
2220e3c1f1c9SMichael Walle {
2221e3c1f1c9SMichael Walle 	struct mtd_info *master = mtd_get_master(mtd);
2222e3c1f1c9SMichael Walle 
2223e3c1f1c9SMichael Walle 	if (!master->_erase_user_prot_reg)
2224e3c1f1c9SMichael Walle 		return -EOPNOTSUPP;
2225e3c1f1c9SMichael Walle 	if (!len)
2226e3c1f1c9SMichael Walle 		return 0;
2227e3c1f1c9SMichael Walle 	return master->_erase_user_prot_reg(master, from, len);
2228e3c1f1c9SMichael Walle }
2229e3c1f1c9SMichael Walle EXPORT_SYMBOL_GPL(mtd_erase_user_prot_reg);
2230e3c1f1c9SMichael Walle 
22318273a0c9SArtem Bityutskiy /* Chip-supported device locking */
mtd_lock(struct mtd_info * mtd,loff_t ofs,uint64_t len)22328273a0c9SArtem Bityutskiy int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
22338273a0c9SArtem Bityutskiy {
223446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
223546b5889cSMiquel Raynal 
223646b5889cSMiquel Raynal 	if (!master->_lock)
22378273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
22380c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
22398273a0c9SArtem Bityutskiy 		return -EINVAL;
2240bcb1d238SArtem Bityutskiy 	if (!len)
2241bcb1d238SArtem Bityutskiy 		return 0;
22429e3307a1SBoris Brezillon 
22439e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
22449e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
22459e3307a1SBoris Brezillon 		len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize;
22469e3307a1SBoris Brezillon 	}
22479e3307a1SBoris Brezillon 
224846b5889cSMiquel Raynal 	return master->_lock(master, mtd_get_master_ofs(mtd, ofs), len);
22498273a0c9SArtem Bityutskiy }
22508273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_lock);
22518273a0c9SArtem Bityutskiy 
mtd_unlock(struct mtd_info * mtd,loff_t ofs,uint64_t len)22528273a0c9SArtem Bityutskiy int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
22538273a0c9SArtem Bityutskiy {
225446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
225546b5889cSMiquel Raynal 
225646b5889cSMiquel Raynal 	if (!master->_unlock)
22578273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
22580c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
22598273a0c9SArtem Bityutskiy 		return -EINVAL;
2260bcb1d238SArtem Bityutskiy 	if (!len)
2261bcb1d238SArtem Bityutskiy 		return 0;
22629e3307a1SBoris Brezillon 
22639e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
22649e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
22659e3307a1SBoris Brezillon 		len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize;
22669e3307a1SBoris Brezillon 	}
22679e3307a1SBoris Brezillon 
226846b5889cSMiquel Raynal 	return master->_unlock(master, mtd_get_master_ofs(mtd, ofs), len);
22698273a0c9SArtem Bityutskiy }
22708273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_unlock);
22718273a0c9SArtem Bityutskiy 
mtd_is_locked(struct mtd_info * mtd,loff_t ofs,uint64_t len)22728273a0c9SArtem Bityutskiy int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
22738273a0c9SArtem Bityutskiy {
227446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
227546b5889cSMiquel Raynal 
227646b5889cSMiquel Raynal 	if (!master->_is_locked)
22778273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
22780c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
22798273a0c9SArtem Bityutskiy 		return -EINVAL;
2280bcb1d238SArtem Bityutskiy 	if (!len)
2281bcb1d238SArtem Bityutskiy 		return 0;
22829e3307a1SBoris Brezillon 
22839e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
22849e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
22859e3307a1SBoris Brezillon 		len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize;
22869e3307a1SBoris Brezillon 	}
22879e3307a1SBoris Brezillon 
228846b5889cSMiquel Raynal 	return master->_is_locked(master, mtd_get_master_ofs(mtd, ofs), len);
22898273a0c9SArtem Bityutskiy }
22908273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_is_locked);
22918273a0c9SArtem Bityutskiy 
mtd_block_isreserved(struct mtd_info * mtd,loff_t ofs)22928471bb73SEzequiel Garcia int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs)
22938273a0c9SArtem Bityutskiy {
229446b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
229546b5889cSMiquel Raynal 
22960c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size)
22978273a0c9SArtem Bityutskiy 		return -EINVAL;
229846b5889cSMiquel Raynal 	if (!master->_block_isreserved)
22998471bb73SEzequiel Garcia 		return 0;
23009e3307a1SBoris Brezillon 
23019e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
23029e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
23039e3307a1SBoris Brezillon 
230446b5889cSMiquel Raynal 	return master->_block_isreserved(master, mtd_get_master_ofs(mtd, ofs));
23058471bb73SEzequiel Garcia }
23068471bb73SEzequiel Garcia EXPORT_SYMBOL_GPL(mtd_block_isreserved);
23078471bb73SEzequiel Garcia 
mtd_block_isbad(struct mtd_info * mtd,loff_t ofs)23088471bb73SEzequiel Garcia int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
23098471bb73SEzequiel Garcia {
231046b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
231146b5889cSMiquel Raynal 
23120c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size)
23138471bb73SEzequiel Garcia 		return -EINVAL;
231446b5889cSMiquel Raynal 	if (!master->_block_isbad)
23158471bb73SEzequiel Garcia 		return 0;
23169e3307a1SBoris Brezillon 
23179e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
23189e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
23199e3307a1SBoris Brezillon 
232046b5889cSMiquel Raynal 	return master->_block_isbad(master, mtd_get_master_ofs(mtd, ofs));
23218273a0c9SArtem Bityutskiy }
23228273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_block_isbad);
23238273a0c9SArtem Bityutskiy 
mtd_block_markbad(struct mtd_info * mtd,loff_t ofs)23248273a0c9SArtem Bityutskiy int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
23258273a0c9SArtem Bityutskiy {
232646b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
232746b5889cSMiquel Raynal 	int ret;
232846b5889cSMiquel Raynal 
232946b5889cSMiquel Raynal 	if (!master->_block_markbad)
23308273a0c9SArtem Bityutskiy 		return -EOPNOTSUPP;
23310c2b4e21SBrian Norris 	if (ofs < 0 || ofs >= mtd->size)
23328273a0c9SArtem Bityutskiy 		return -EINVAL;
2333664addc2SArtem Bityutskiy 	if (!(mtd->flags & MTD_WRITEABLE))
2334664addc2SArtem Bityutskiy 		return -EROFS;
233546b5889cSMiquel Raynal 
23369e3307a1SBoris Brezillon 	if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
23379e3307a1SBoris Brezillon 		ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize;
23389e3307a1SBoris Brezillon 
233946b5889cSMiquel Raynal 	ret = master->_block_markbad(master, mtd_get_master_ofs(mtd, ofs));
234046b5889cSMiquel Raynal 	if (ret)
234146b5889cSMiquel Raynal 		return ret;
234246b5889cSMiquel Raynal 
234346b5889cSMiquel Raynal 	while (mtd->parent) {
234446b5889cSMiquel Raynal 		mtd->ecc_stats.badblocks++;
234546b5889cSMiquel Raynal 		mtd = mtd->parent;
234646b5889cSMiquel Raynal 	}
234746b5889cSMiquel Raynal 
234846b5889cSMiquel Raynal 	return 0;
23498273a0c9SArtem Bityutskiy }
23508273a0c9SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_block_markbad);
23518273a0c9SArtem Bityutskiy 
23528273a0c9SArtem Bityutskiy /*
235352b02031SArtem Bityutskiy  * default_mtd_writev - the default writev method
235452b02031SArtem Bityutskiy  * @mtd: mtd device description object pointer
235552b02031SArtem Bityutskiy  * @vecs: the vectors to write
235652b02031SArtem Bityutskiy  * @count: count of vectors in @vecs
235752b02031SArtem Bityutskiy  * @to: the MTD device offset to write to
235852b02031SArtem Bityutskiy  * @retlen: on exit contains the count of bytes written to the MTD device.
235952b02031SArtem Bityutskiy  *
236052b02031SArtem Bityutskiy  * This function returns zero in case of success and a negative error code in
236152b02031SArtem Bityutskiy  * case of failure.
23621da177e4SLinus Torvalds  */
default_mtd_writev(struct mtd_info * mtd,const struct kvec * vecs,unsigned long count,loff_t to,size_t * retlen)23631dbebd32SArtem Bityutskiy static int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
23641da177e4SLinus Torvalds 			      unsigned long count, loff_t to, size_t *retlen)
23651da177e4SLinus Torvalds {
23661da177e4SLinus Torvalds 	unsigned long i;
23671da177e4SLinus Torvalds 	size_t totlen = 0, thislen;
23681da177e4SLinus Torvalds 	int ret = 0;
23691da177e4SLinus Torvalds 
23701da177e4SLinus Torvalds 	for (i = 0; i < count; i++) {
23711da177e4SLinus Torvalds 		if (!vecs[i].iov_len)
23721da177e4SLinus Torvalds 			continue;
2373eda95cbfSArtem Bityutskiy 		ret = mtd_write(mtd, to, vecs[i].iov_len, &thislen,
2374eda95cbfSArtem Bityutskiy 				vecs[i].iov_base);
23751da177e4SLinus Torvalds 		totlen += thislen;
23761da177e4SLinus Torvalds 		if (ret || thislen != vecs[i].iov_len)
23771da177e4SLinus Torvalds 			break;
23781da177e4SLinus Torvalds 		to += vecs[i].iov_len;
23791da177e4SLinus Torvalds 	}
23801da177e4SLinus Torvalds 	*retlen = totlen;
23811da177e4SLinus Torvalds 	return ret;
23821da177e4SLinus Torvalds }
23831dbebd32SArtem Bityutskiy 
23841dbebd32SArtem Bityutskiy /*
23851dbebd32SArtem Bityutskiy  * mtd_writev - the vector-based MTD write method
23861dbebd32SArtem Bityutskiy  * @mtd: mtd device description object pointer
23871dbebd32SArtem Bityutskiy  * @vecs: the vectors to write
23881dbebd32SArtem Bityutskiy  * @count: count of vectors in @vecs
23891dbebd32SArtem Bityutskiy  * @to: the MTD device offset to write to
23901dbebd32SArtem Bityutskiy  * @retlen: on exit contains the count of bytes written to the MTD device.
23911dbebd32SArtem Bityutskiy  *
23921dbebd32SArtem Bityutskiy  * This function returns zero in case of success and a negative error code in
23931dbebd32SArtem Bityutskiy  * case of failure.
23941dbebd32SArtem Bityutskiy  */
mtd_writev(struct mtd_info * mtd,const struct kvec * vecs,unsigned long count,loff_t to,size_t * retlen)23951dbebd32SArtem Bityutskiy int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
23961dbebd32SArtem Bityutskiy 	       unsigned long count, loff_t to, size_t *retlen)
23971dbebd32SArtem Bityutskiy {
239846b5889cSMiquel Raynal 	struct mtd_info *master = mtd_get_master(mtd);
239946b5889cSMiquel Raynal 
24001dbebd32SArtem Bityutskiy 	*retlen = 0;
2401664addc2SArtem Bityutskiy 	if (!(mtd->flags & MTD_WRITEABLE))
2402664addc2SArtem Bityutskiy 		return -EROFS;
240346b5889cSMiquel Raynal 
240446b5889cSMiquel Raynal 	if (!master->_writev)
24051dbebd32SArtem Bityutskiy 		return default_mtd_writev(mtd, vecs, count, to, retlen);
240646b5889cSMiquel Raynal 
240746b5889cSMiquel Raynal 	return master->_writev(master, vecs, count,
240846b5889cSMiquel Raynal 			       mtd_get_master_ofs(mtd, to), retlen);
24091dbebd32SArtem Bityutskiy }
24101dbebd32SArtem Bityutskiy EXPORT_SYMBOL_GPL(mtd_writev);
24111da177e4SLinus Torvalds 
241233b53716SGrant Erickson /**
241333b53716SGrant Erickson  * mtd_kmalloc_up_to - allocate a contiguous buffer up to the specified size
241452b02031SArtem Bityutskiy  * @mtd: mtd device description object pointer
241552b02031SArtem Bityutskiy  * @size: a pointer to the ideal or maximum size of the allocation, points
241633b53716SGrant Erickson  *        to the actual allocation size on success.
241733b53716SGrant Erickson  *
241833b53716SGrant Erickson  * This routine attempts to allocate a contiguous kernel buffer up to
241933b53716SGrant Erickson  * the specified size, backing off the size of the request exponentially
242033b53716SGrant Erickson  * until the request succeeds or until the allocation size falls below
242133b53716SGrant Erickson  * the system page size. This attempts to make sure it does not adversely
242233b53716SGrant Erickson  * impact system performance, so when allocating more than one page, we
2423caf49191SLinus Torvalds  * ask the memory allocator to avoid re-trying, swapping, writing back
2424caf49191SLinus Torvalds  * or performing I/O.
242533b53716SGrant Erickson  *
242633b53716SGrant Erickson  * Note, this function also makes sure that the allocated buffer is aligned to
242733b53716SGrant Erickson  * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value.
242833b53716SGrant Erickson  *
242933b53716SGrant Erickson  * This is called, for example by mtd_{read,write} and jffs2_scan_medium,
243033b53716SGrant Erickson  * to handle smaller (i.e. degraded) buffer allocations under low- or
243133b53716SGrant Erickson  * fragmented-memory situations where such reduced allocations, from a
243233b53716SGrant Erickson  * requested ideal, are allowed.
243333b53716SGrant Erickson  *
243433b53716SGrant Erickson  * Returns a pointer to the allocated buffer on success; otherwise, NULL.
243533b53716SGrant Erickson  */
mtd_kmalloc_up_to(const struct mtd_info * mtd,size_t * size)243633b53716SGrant Erickson void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
243733b53716SGrant Erickson {
2438d0164adcSMel Gorman 	gfp_t flags = __GFP_NOWARN | __GFP_DIRECT_RECLAIM | __GFP_NORETRY;
243933b53716SGrant Erickson 	size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
244033b53716SGrant Erickson 	void *kbuf;
244133b53716SGrant Erickson 
244233b53716SGrant Erickson 	*size = min_t(size_t, *size, KMALLOC_MAX_SIZE);
244333b53716SGrant Erickson 
244433b53716SGrant Erickson 	while (*size > min_alloc) {
244533b53716SGrant Erickson 		kbuf = kmalloc(*size, flags);
244633b53716SGrant Erickson 		if (kbuf)
244733b53716SGrant Erickson 			return kbuf;
244833b53716SGrant Erickson 
244933b53716SGrant Erickson 		*size >>= 1;
245033b53716SGrant Erickson 		*size = ALIGN(*size, mtd->writesize);
245133b53716SGrant Erickson 	}
245233b53716SGrant Erickson 
245333b53716SGrant Erickson 	/*
245433b53716SGrant Erickson 	 * For the last resort allocation allow 'kmalloc()' to do all sorts of
245533b53716SGrant Erickson 	 * things (write-back, dropping caches, etc) by using GFP_KERNEL.
245633b53716SGrant Erickson 	 */
245733b53716SGrant Erickson 	return kmalloc(*size, GFP_KERNEL);
245833b53716SGrant Erickson }
245933b53716SGrant Erickson EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
24601da177e4SLinus Torvalds 
24612d2dce0eSPavel Machek #ifdef CONFIG_PROC_FS
24622d2dce0eSPavel Machek 
24631da177e4SLinus Torvalds /*====================================================================*/
24641da177e4SLinus Torvalds /* Support for /proc/mtd */
24651da177e4SLinus Torvalds 
mtd_proc_show(struct seq_file * m,void * v)2466447d9bd8SAlexey Dobriyan static int mtd_proc_show(struct seq_file *m, void *v)
24671da177e4SLinus Torvalds {
2468f1332ba2SBen Hutchings 	struct mtd_info *mtd;
24691da177e4SLinus Torvalds 
2470447d9bd8SAlexey Dobriyan 	seq_puts(m, "dev:    size   erasesize  name\n");
247148b19268SIngo Molnar 	mutex_lock(&mtd_table_mutex);
2472f1332ba2SBen Hutchings 	mtd_for_each_device(mtd) {
2473447d9bd8SAlexey Dobriyan 		seq_printf(m, "mtd%d: %8.8llx %8.8x \"%s\"\n",
2474447d9bd8SAlexey Dobriyan 			   mtd->index, (unsigned long long)mtd->size,
2475447d9bd8SAlexey Dobriyan 			   mtd->erasesize, mtd->name);
24761da177e4SLinus Torvalds 	}
247748b19268SIngo Molnar 	mutex_unlock(&mtd_table_mutex);
24781da177e4SLinus Torvalds 	return 0;
24791da177e4SLinus Torvalds }
248045b09076SKevin Cernekee #endif /* CONFIG_PROC_FS */
248145b09076SKevin Cernekee 
24821da177e4SLinus Torvalds /*====================================================================*/
24831da177e4SLinus Torvalds /* Init code */
24841da177e4SLinus Torvalds 
mtd_bdi_init(const char * name)2485462d69a2STomas Winkler static struct backing_dev_info * __init mtd_bdi_init(const char *name)
24860661b1acSJens Axboe {
2487445caaa2SSteve Longerbeam 	struct backing_dev_info *bdi;
24880661b1acSJens Axboe 	int ret;
24890661b1acSJens Axboe 
2490aef33c2fSChristoph Hellwig 	bdi = bdi_alloc(NUMA_NO_NODE);
2491445caaa2SSteve Longerbeam 	if (!bdi)
2492445caaa2SSteve Longerbeam 		return ERR_PTR(-ENOMEM);
249355b2598eSChristoph Hellwig 	bdi->ra_pages = 0;
249455b2598eSChristoph Hellwig 	bdi->io_pages = 0;
24950661b1acSJens Axboe 
2496fa06052dSJan Kara 	/*
2497fa06052dSJan Kara 	 * We put '-0' suffix to the name to get the same name format as we
2498fa06052dSJan Kara 	 * used to get. Since this is called only once, we get a unique name.
2499fa06052dSJan Kara 	 */
25007c4cc300SJan Kara 	ret = bdi_register(bdi, "%.28s-0", name);
25010661b1acSJens Axboe 	if (ret)
2502fa06052dSJan Kara 		bdi_put(bdi);
25030661b1acSJens Axboe 
2504445caaa2SSteve Longerbeam 	return ret ? ERR_PTR(ret) : bdi;
25050661b1acSJens Axboe }
25060661b1acSJens Axboe 
250793e56214SArtem Bityutskiy static struct proc_dir_entry *proc_mtd;
250893e56214SArtem Bityutskiy 
init_mtd(void)25091da177e4SLinus Torvalds static int __init init_mtd(void)
25101da177e4SLinus Torvalds {
251115bce40cSDavid Woodhouse 	int ret;
2512694bb7fcSKevin Cernekee 
25130661b1acSJens Axboe 	ret = class_register(&mtd_class);
25140661b1acSJens Axboe 	if (ret)
25150661b1acSJens Axboe 		goto err_reg;
25160661b1acSJens Axboe 
2517445caaa2SSteve Longerbeam 	mtd_bdi = mtd_bdi_init("mtd");
2518445caaa2SSteve Longerbeam 	if (IS_ERR(mtd_bdi)) {
2519445caaa2SSteve Longerbeam 		ret = PTR_ERR(mtd_bdi);
2520b4caecd4SChristoph Hellwig 		goto err_bdi;
2521445caaa2SSteve Longerbeam 	}
25220661b1acSJens Axboe 
25233f3942acSChristoph Hellwig 	proc_mtd = proc_create_single("mtd", 0, NULL, mtd_proc_show);
252493e56214SArtem Bityutskiy 
2525660685d9SArtem Bityutskiy 	ret = init_mtdchar();
2526660685d9SArtem Bityutskiy 	if (ret)
2527660685d9SArtem Bityutskiy 		goto out_procfs;
2528660685d9SArtem Bityutskiy 
2529e8e3edb9SMario Rugiero 	dfs_dir_mtd = debugfs_create_dir("mtd", NULL);
253067b967ddSMiquel Raynal 	debugfs_create_bool("expert_analysis_mode", 0600, dfs_dir_mtd,
253167b967ddSMiquel Raynal 			    &mtd_expert_analysis_mode);
2532e8e3edb9SMario Rugiero 
25331da177e4SLinus Torvalds 	return 0;
25340661b1acSJens Axboe 
2535660685d9SArtem Bityutskiy out_procfs:
2536660685d9SArtem Bityutskiy 	if (proc_mtd)
2537660685d9SArtem Bityutskiy 		remove_proc_entry("mtd", NULL);
25381aadf01eSGaosheng Cui 	bdi_unregister(mtd_bdi);
2539fa06052dSJan Kara 	bdi_put(mtd_bdi);
2540b4caecd4SChristoph Hellwig err_bdi:
25410661b1acSJens Axboe 	class_unregister(&mtd_class);
25420661b1acSJens Axboe err_reg:
25430661b1acSJens Axboe 	pr_err("Error registering mtd class or bdi: %d\n", ret);
25440661b1acSJens Axboe 	return ret;
25451da177e4SLinus Torvalds }
25461da177e4SLinus Torvalds 
cleanup_mtd(void)25471da177e4SLinus Torvalds static void __exit cleanup_mtd(void)
25481da177e4SLinus Torvalds {
2549e8e3edb9SMario Rugiero 	debugfs_remove_recursive(dfs_dir_mtd);
2550660685d9SArtem Bityutskiy 	cleanup_mtdchar();
25511da177e4SLinus Torvalds 	if (proc_mtd)
25521da177e4SLinus Torvalds 		remove_proc_entry("mtd", NULL);
255315bce40cSDavid Woodhouse 	class_unregister(&mtd_class);
25549718c59cSChristoph Hellwig 	bdi_unregister(mtd_bdi);
2555fa06052dSJan Kara 	bdi_put(mtd_bdi);
255635667b99SJohannes Thumshirn 	idr_destroy(&mtd_idr);
25571da177e4SLinus Torvalds }
25581da177e4SLinus Torvalds 
25591da177e4SLinus Torvalds module_init(init_mtd);
25601da177e4SLinus Torvalds module_exit(cleanup_mtd);
25611da177e4SLinus Torvalds 
25621da177e4SLinus Torvalds MODULE_LICENSE("GPL");
25631da177e4SLinus Torvalds MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
25641da177e4SLinus Torvalds MODULE_DESCRIPTION("Core MTD registration and access routines");
2565