|
@@ -0,0 +1,264 @@
|
|
|
+From 471a17d8d1b838092d1a76e48cdce8b5b67ff809 Mon Sep 17 00:00:00 2001
|
|
|
+From: Daniel Golle <[email protected]>
|
|
|
+Date: Mon, 27 Nov 2023 01:54:28 +0000
|
|
|
+Subject: [PATCH 04/15] mtd: ubi: attach from device tree
|
|
|
+
|
|
|
+Introduce device tree compatible 'linux,ubi' and attach compatible MTD
|
|
|
+devices using the MTD add notifier. This is needed for a UBI device to
|
|
|
+be available early at boot (and not only after late_initcall), so
|
|
|
+volumes on them can be used eg. as NVMEM providers for other drivers.
|
|
|
+
|
|
|
+Signed-off-by: Daniel Golle <[email protected]>
|
|
|
+---
|
|
|
+ drivers/mtd/ubi/build.c | 146 ++++++++++++++++++++++++++++------------
|
|
|
+ drivers/mtd/ubi/cdev.c | 2 +-
|
|
|
+ drivers/mtd/ubi/ubi.h | 2 +-
|
|
|
+ 3 files changed, 106 insertions(+), 44 deletions(-)
|
|
|
+
|
|
|
+--- a/drivers/mtd/ubi/build.c
|
|
|
++++ b/drivers/mtd/ubi/build.c
|
|
|
+@@ -27,6 +27,7 @@
|
|
|
+ #include <linux/log2.h>
|
|
|
+ #include <linux/kthread.h>
|
|
|
+ #include <linux/kernel.h>
|
|
|
++#include <linux/of.h>
|
|
|
+ #include <linux/slab.h>
|
|
|
+ #include <linux/major.h>
|
|
|
+ #include "ubi.h"
|
|
|
+@@ -1071,6 +1072,7 @@ out_free:
|
|
|
+ * ubi_detach_mtd_dev - detach an MTD device.
|
|
|
+ * @ubi_num: UBI device number to detach from
|
|
|
+ * @anyway: detach MTD even if device reference count is not zero
|
|
|
++ * @have_lock: called by MTD notifier holding mtd_table_mutex
|
|
|
+ *
|
|
|
+ * This function destroys an UBI device number @ubi_num and detaches the
|
|
|
+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
|
|
|
+@@ -1080,7 +1082,7 @@ out_free:
|
|
|
+ * Note, the invocations of this function has to be serialized by the
|
|
|
+ * @ubi_devices_mutex.
|
|
|
+ */
|
|
|
+-int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
|
|
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
|
|
|
+ {
|
|
|
+ struct ubi_device *ubi;
|
|
|
+
|
|
|
+@@ -1136,7 +1138,11 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
|
|
+ vfree(ubi->peb_buf);
|
|
|
+ vfree(ubi->fm_buf);
|
|
|
+ ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
|
|
|
+- put_mtd_device(ubi->mtd);
|
|
|
++ if (have_lock)
|
|
|
++ __put_mtd_device(ubi->mtd);
|
|
|
++ else
|
|
|
++ put_mtd_device(ubi->mtd);
|
|
|
++
|
|
|
+ put_device(&ubi->dev);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+@@ -1213,43 +1219,43 @@ static struct mtd_info * __init open_mtd
|
|
|
+ return mtd;
|
|
|
+ }
|
|
|
+
|
|
|
+-static int __init ubi_init(void)
|
|
|
++static void ubi_notify_add(struct mtd_info *mtd)
|
|
|
+ {
|
|
|
+- int err, i, k;
|
|
|
++ struct device_node *np = mtd_get_of_node(mtd);
|
|
|
++ int err;
|
|
|
+
|
|
|
+- /* Ensure that EC and VID headers have correct size */
|
|
|
+- BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
|
|
|
+- BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
|
|
|
++ if (!of_device_is_compatible(np, "linux,ubi"))
|
|
|
++ return;
|
|
|
+
|
|
|
+- if (mtd_devs > UBI_MAX_DEVICES) {
|
|
|
+- pr_err("UBI error: too many MTD devices, maximum is %d\n",
|
|
|
+- UBI_MAX_DEVICES);
|
|
|
+- return -EINVAL;
|
|
|
+- }
|
|
|
++ /*
|
|
|
++ * we are already holding &mtd_table_mutex, but still need
|
|
|
++ * to bump refcount
|
|
|
++ */
|
|
|
++ err = __get_mtd_device(mtd);
|
|
|
++ if (err)
|
|
|
++ return;
|
|
|
+
|
|
|
+- /* Create base sysfs directory and sysfs files */
|
|
|
+- err = class_register(&ubi_class);
|
|
|
++ /* called while holding mtd_table_mutex */
|
|
|
++ mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
|
|
|
++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
|
|
|
++ mutex_unlock(&ubi_devices_mutex);
|
|
|
+ if (err < 0)
|
|
|
+- return err;
|
|
|
+-
|
|
|
+- err = misc_register(&ubi_ctrl_cdev);
|
|
|
+- if (err) {
|
|
|
+- pr_err("UBI error: cannot register device\n");
|
|
|
+- goto out;
|
|
|
+- }
|
|
|
++ __put_mtd_device(mtd);
|
|
|
++}
|
|
|
+
|
|
|
+- ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
|
|
|
+- sizeof(struct ubi_wl_entry),
|
|
|
+- 0, 0, NULL);
|
|
|
+- if (!ubi_wl_entry_slab) {
|
|
|
+- err = -ENOMEM;
|
|
|
+- goto out_dev_unreg;
|
|
|
+- }
|
|
|
++static void ubi_notify_remove(struct mtd_info *mtd)
|
|
|
++{
|
|
|
++ WARN(1, "mtd%d removed despite UBI still being attached", mtd->index);
|
|
|
++}
|
|
|
+
|
|
|
+- err = ubi_debugfs_init();
|
|
|
+- if (err)
|
|
|
+- goto out_slab;
|
|
|
++static struct mtd_notifier ubi_mtd_notifier = {
|
|
|
++ .add = ubi_notify_add,
|
|
|
++ .remove = ubi_notify_remove,
|
|
|
++};
|
|
|
+
|
|
|
++static int __init ubi_init_attach(void)
|
|
|
++{
|
|
|
++ int err, i, k;
|
|
|
+
|
|
|
+ /* Attach MTD devices */
|
|
|
+ for (i = 0; i < mtd_devs; i++) {
|
|
|
+@@ -1297,25 +1303,79 @@ static int __init ubi_init(void)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
++ return 0;
|
|
|
++
|
|
|
++out_detach:
|
|
|
++ for (k = 0; k < i; k++)
|
|
|
++ if (ubi_devices[k]) {
|
|
|
++ mutex_lock(&ubi_devices_mutex);
|
|
|
++ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1, false);
|
|
|
++ mutex_unlock(&ubi_devices_mutex);
|
|
|
++ }
|
|
|
++ return err;
|
|
|
++}
|
|
|
++#ifndef CONFIG_MTD_UBI_MODULE
|
|
|
++late_initcall(ubi_init_attach);
|
|
|
++#endif
|
|
|
++
|
|
|
++static int __init ubi_init(void)
|
|
|
++{
|
|
|
++ int err;
|
|
|
++
|
|
|
++ /* Ensure that EC and VID headers have correct size */
|
|
|
++ BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
|
|
|
++ BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
|
|
|
++
|
|
|
++ if (mtd_devs > UBI_MAX_DEVICES) {
|
|
|
++ pr_err("UBI error: too many MTD devices, maximum is %d\n",
|
|
|
++ UBI_MAX_DEVICES);
|
|
|
++ return -EINVAL;
|
|
|
++ }
|
|
|
++
|
|
|
++ /* Create base sysfs directory and sysfs files */
|
|
|
++ err = class_register(&ubi_class);
|
|
|
++ if (err < 0)
|
|
|
++ return err;
|
|
|
++
|
|
|
++ err = misc_register(&ubi_ctrl_cdev);
|
|
|
++ if (err) {
|
|
|
++ pr_err("UBI error: cannot register device\n");
|
|
|
++ goto out;
|
|
|
++ }
|
|
|
++
|
|
|
++ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
|
|
|
++ sizeof(struct ubi_wl_entry),
|
|
|
++ 0, 0, NULL);
|
|
|
++ if (!ubi_wl_entry_slab) {
|
|
|
++ err = -ENOMEM;
|
|
|
++ goto out_dev_unreg;
|
|
|
++ }
|
|
|
++
|
|
|
++ err = ubi_debugfs_init();
|
|
|
++ if (err)
|
|
|
++ goto out_slab;
|
|
|
++
|
|
|
+ err = ubiblock_init();
|
|
|
+ if (err) {
|
|
|
+ pr_err("UBI error: block: cannot initialize, error %d\n", err);
|
|
|
+
|
|
|
+ /* See comment above re-ubi_is_module(). */
|
|
|
+ if (ubi_is_module())
|
|
|
+- goto out_detach;
|
|
|
++ goto out_slab;
|
|
|
++ }
|
|
|
++
|
|
|
++ register_mtd_user(&ubi_mtd_notifier);
|
|
|
++
|
|
|
++ if (ubi_is_module()) {
|
|
|
++ err = ubi_init_attach();
|
|
|
++ if (err)
|
|
|
++ goto out_mtd_notifier;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+-out_detach:
|
|
|
+- for (k = 0; k < i; k++)
|
|
|
+- if (ubi_devices[k]) {
|
|
|
+- mutex_lock(&ubi_devices_mutex);
|
|
|
+- ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
|
|
|
+- mutex_unlock(&ubi_devices_mutex);
|
|
|
+- }
|
|
|
+- ubi_debugfs_exit();
|
|
|
++out_mtd_notifier:
|
|
|
++ unregister_mtd_user(&ubi_mtd_notifier);
|
|
|
+ out_slab:
|
|
|
+ kmem_cache_destroy(ubi_wl_entry_slab);
|
|
|
+ out_dev_unreg:
|
|
|
+@@ -1325,18 +1385,20 @@ out:
|
|
|
+ pr_err("UBI error: cannot initialize UBI, error %d\n", err);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+-late_initcall(ubi_init);
|
|
|
++device_initcall(ubi_init);
|
|
|
++
|
|
|
+
|
|
|
+ static void __exit ubi_exit(void)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+
|
|
|
+ ubiblock_exit();
|
|
|
++ unregister_mtd_user(&ubi_mtd_notifier);
|
|
|
+
|
|
|
+ for (i = 0; i < UBI_MAX_DEVICES; i++)
|
|
|
+ if (ubi_devices[i]) {
|
|
|
+ mutex_lock(&ubi_devices_mutex);
|
|
|
+- ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
|
|
|
++ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, false);
|
|
|
+ mutex_unlock(&ubi_devices_mutex);
|
|
|
+ }
|
|
|
+ ubi_debugfs_exit();
|
|
|
+--- a/drivers/mtd/ubi/cdev.c
|
|
|
++++ b/drivers/mtd/ubi/cdev.c
|
|
|
+@@ -1065,7 +1065,7 @@ static long ctrl_cdev_ioctl(struct file
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_lock(&ubi_devices_mutex);
|
|
|
+- err = ubi_detach_mtd_dev(ubi_num, 0);
|
|
|
++ err = ubi_detach_mtd_dev(ubi_num, 0, false);
|
|
|
+ mutex_unlock(&ubi_devices_mutex);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+--- a/drivers/mtd/ubi/ubi.h
|
|
|
++++ b/drivers/mtd/ubi/ubi.h
|
|
|
+@@ -939,7 +939,7 @@ int ubi_io_write_vid_hdr(struct ubi_devi
|
|
|
+ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
|
|
+ int vid_hdr_offset, int max_beb_per1024,
|
|
|
+ bool disable_fm);
|
|
|
+-int ubi_detach_mtd_dev(int ubi_num, int anyway);
|
|
|
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock);
|
|
|
+ struct ubi_device *ubi_get_device(int ubi_num);
|
|
|
+ void ubi_put_device(struct ubi_device *ubi);
|
|
|
+ struct ubi_device *ubi_get_by_major(int major);
|