mtdcore.c (2f98e686ef59b5d19af5847d755798e2031bee3a) mtdcore.c (19bfa9ebebb5ec0695def57eb1d80de7e9cab369)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Core registration and callback routines for MTD
4 * drivers and users.
5 *
6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
7 * Copyright © 2006 Red Hat UK Limited
8 */

--- 79 unchanged lines hidden (view full) ---

88/* REVISIT once MTD uses the driver model better, whoever allocates
89 * the mtd_info will probably want to use the release() hook...
90 */
91static void mtd_release(struct device *dev)
92{
93 struct mtd_info *mtd = dev_get_drvdata(dev);
94 dev_t index = MTD_DEVT(mtd->index);
95
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Core registration and callback routines for MTD
4 * drivers and users.
5 *
6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
7 * Copyright © 2006 Red Hat UK Limited
8 */

--- 79 unchanged lines hidden (view full) ---

88/* REVISIT once MTD uses the driver model better, whoever allocates
89 * the mtd_info will probably want to use the release() hook...
90 */
91static void mtd_release(struct device *dev)
92{
93 struct mtd_info *mtd = dev_get_drvdata(dev);
94 dev_t index = MTD_DEVT(mtd->index);
95
96 if (mtd_is_partition(mtd))
97 release_mtd_partition(mtd);
98
96 /* remove /dev/mtdXro node */
97 device_destroy(&mtd_class, index + 1);
98}
99
99 /* remove /dev/mtdXro node */
100 device_destroy(&mtd_class, index + 1);
101}
102
103static void mtd_device_release(struct kref *kref)
104{
105 struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
106
107 debugfs_remove_recursive(mtd->dbg.dfs_dir);
108
109 /* Try to remove the NVMEM provider */
110 nvmem_unregister(mtd->nvmem);
111
112 device_unregister(&mtd->dev);
113
114 /* Clear dev so mtd can be safely re-registered later if desired */
115 memset(&mtd->dev, 0, sizeof(mtd->dev));
116
117 idr_remove(&mtd_idr, mtd->index);
118 of_node_put(mtd_get_of_node(mtd));
119
120 module_put(THIS_MODULE);
121}
122
100#define MTD_DEVICE_ATTR_RO(name) \
101static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL)
102
103#define MTD_DEVICE_ATTR_RW(name) \
104static DEVICE_ATTR(name, 0644, mtd_##name##_show, mtd_##name##_store)
105
106static ssize_t mtd_type_show(struct device *dev,
107 struct device_attribute *attr, char *buf)

--- 553 unchanged lines hidden (view full) ---

661 else
662 i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
663 if (i < 0) {
664 error = i;
665 goto fail_locked;
666 }
667
668 mtd->index = i;
123#define MTD_DEVICE_ATTR_RO(name) \
124static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL)
125
126#define MTD_DEVICE_ATTR_RW(name) \
127static DEVICE_ATTR(name, 0644, mtd_##name##_show, mtd_##name##_store)
128
129static ssize_t mtd_type_show(struct device *dev,
130 struct device_attribute *attr, char *buf)

--- 553 unchanged lines hidden (view full) ---

684 else
685 i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
686 if (i < 0) {
687 error = i;
688 goto fail_locked;
689 }
690
691 mtd->index = i;
669 mtd->usecount = 0;
692 kref_init(&mtd->refcnt);
670
671 /* default value if not set by driver */
672 if (mtd->bitflip_threshold == 0)
673 mtd->bitflip_threshold = mtd->ecc_strength;
674
675 if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
676 int ngroups = mtd_pairing_groups(master);
677

--- 96 unchanged lines hidden (view full) ---

774 * Returns zero on success or 1 on failure, which currently will happen
775 * if the requested device does not appear to be present in the list.
776 */
777
778int del_mtd_device(struct mtd_info *mtd)
779{
780 int ret;
781 struct mtd_notifier *not;
693
694 /* default value if not set by driver */
695 if (mtd->bitflip_threshold == 0)
696 mtd->bitflip_threshold = mtd->ecc_strength;
697
698 if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) {
699 int ngroups = mtd_pairing_groups(master);
700

--- 96 unchanged lines hidden (view full) ---

797 * Returns zero on success or 1 on failure, which currently will happen
798 * if the requested device does not appear to be present in the list.
799 */
800
801int del_mtd_device(struct mtd_info *mtd)
802{
803 int ret;
804 struct mtd_notifier *not;
782 struct device_node *mtd_of_node;
783
784 mutex_lock(&mtd_table_mutex);
785
786 if (idr_find(&mtd_idr, mtd->index) != mtd) {
787 ret = -ENODEV;
788 goto out_error;
789 }
790
791 /* No need to get a refcount on the module containing
792 the notifier, since we hold the mtd_table_mutex */
793 list_for_each_entry(not, &mtd_notifiers, list)
794 not->remove(mtd);
795
805
806 mutex_lock(&mtd_table_mutex);
807
808 if (idr_find(&mtd_idr, mtd->index) != mtd) {
809 ret = -ENODEV;
810 goto out_error;
811 }
812
813 /* No need to get a refcount on the module containing
814 the notifier, since we hold the mtd_table_mutex */
815 list_for_each_entry(not, &mtd_notifiers, list)
816 not->remove(mtd);
817
796 if (mtd->usecount) {
797 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
798 mtd->index, mtd->name, mtd->usecount);
799 ret = -EBUSY;
800 } else {
801 mtd_of_node = mtd_get_of_node(mtd);
802 debugfs_remove_recursive(mtd->dbg.dfs_dir);
818 kref_put(&mtd->refcnt, mtd_device_release);
819 ret = 0;
803
820
804 /* Try to remove the NVMEM provider */
805 nvmem_unregister(mtd->nvmem);
806
807 device_unregister(&mtd->dev);
808
809 /* Clear dev so mtd can be safely re-registered later if desired */
810 memset(&mtd->dev, 0, sizeof(mtd->dev));
811
812 idr_remove(&mtd_idr, mtd->index);
813 of_node_put(mtd_of_node);
814
815 module_put(THIS_MODULE);
816 ret = 0;
817 }
818
819out_error:
820 mutex_unlock(&mtd_table_mutex);
821 return ret;
822}
823
824/*
825 * Set a few defaults based on the parent devices, if not provided by the
826 * driver

--- 398 unchanged lines hidden (view full) ---

1225int __get_mtd_device(struct mtd_info *mtd)
1226{
1227 struct mtd_info *master = mtd_get_master(mtd);
1228 int err;
1229
1230 if (!try_module_get(master->owner))
1231 return -ENODEV;
1232
821out_error:
822 mutex_unlock(&mtd_table_mutex);
823 return ret;
824}
825
826/*
827 * Set a few defaults based on the parent devices, if not provided by the
828 * driver

--- 398 unchanged lines hidden (view full) ---

1227int __get_mtd_device(struct mtd_info *mtd)
1228{
1229 struct mtd_info *master = mtd_get_master(mtd);
1230 int err;
1231
1232 if (!try_module_get(master->owner))
1233 return -ENODEV;
1234
1235 kref_get(&mtd->refcnt);
1236
1233 if (master->_get_device) {
1234 err = master->_get_device(mtd);
1235
1236 if (err) {
1237 if (master->_get_device) {
1238 err = master->_get_device(mtd);
1239
1240 if (err) {
1241 kref_put(&mtd->refcnt, mtd_device_release);
1237 module_put(master->owner);
1238 return err;
1239 }
1240 }
1241
1242 module_put(master->owner);
1243 return err;
1244 }
1245 }
1246
1242 master->usecount++;
1243
1244 while (mtd->parent) {
1247 while (mtd->parent) {
1245 mtd->usecount++;
1248 if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd->parent != master)
1249 kref_get(&mtd->parent->refcnt);
1246 mtd = mtd->parent;
1247 }
1248
1249 return 0;
1250}
1251EXPORT_SYMBOL_GPL(__get_mtd_device);
1252
1253/**

--- 70 unchanged lines hidden (view full) ---

1324
1325}
1326EXPORT_SYMBOL_GPL(put_mtd_device);
1327
1328void __put_mtd_device(struct mtd_info *mtd)
1329{
1330 struct mtd_info *master = mtd_get_master(mtd);
1331
1250 mtd = mtd->parent;
1251 }
1252
1253 return 0;
1254}
1255EXPORT_SYMBOL_GPL(__get_mtd_device);
1256
1257/**

--- 70 unchanged lines hidden (view full) ---

1328
1329}
1330EXPORT_SYMBOL_GPL(put_mtd_device);
1331
1332void __put_mtd_device(struct mtd_info *mtd)
1333{
1334 struct mtd_info *master = mtd_get_master(mtd);
1335
1332 while (mtd->parent) {
1333 --mtd->usecount;
1334 BUG_ON(mtd->usecount < 0);
1335 mtd = mtd->parent;
1336 while (mtd != master) {
1337 struct mtd_info *parent = mtd->parent;
1338
1339 kref_put(&mtd->refcnt, mtd_device_release);
1340 mtd = parent;
1336 }
1337
1341 }
1342
1338 master->usecount--;
1339
1340 if (master->_put_device)
1341 master->_put_device(master);
1342
1343 module_put(master->owner);
1343 if (master->_put_device)
1344 master->_put_device(master);
1345
1346 module_put(master->owner);
1347
1348 if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
1349 kref_put(&master->refcnt, mtd_device_release);
1344}
1345EXPORT_SYMBOL_GPL(__put_mtd_device);
1346
1347/*
1348 * Erase is an synchronous operation. Device drivers are epected to return a
1349 * negative error code if the operation failed and update instr->fail_addr
1350 * to point the portion that was not properly erased.
1351 */

--- 1194 unchanged lines hidden ---
1350}
1351EXPORT_SYMBOL_GPL(__put_mtd_device);
1352
1353/*
1354 * Erase is an synchronous operation. Device drivers are epected to return a
1355 * negative error code if the operation failed and update instr->fail_addr
1356 * to point the portion that was not properly erased.
1357 */

--- 1194 unchanged lines hidden ---