]> Git Repo - J-linux.git/commitdiff
mtd: ubi: attach from device tree
authorDaniel Golle <[email protected]>
Tue, 19 Dec 2023 02:33:14 +0000 (02:33 +0000)
committerRichard Weinberger <[email protected]>
Sun, 25 Feb 2024 21:41:33 +0000 (22:41 +0100)
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]>
Signed-off-by: Richard Weinberger <[email protected]>
drivers/mtd/ubi/build.c

index 7d4ff1193db6f04a114b1e0fcdde3984644607d1..8c3f763e4ddb814488fb3040f663f2387fa321d4 100644 (file)
@@ -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"
@@ -1219,43 +1220,43 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
        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, 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)
+{
+       /* do nothing for now */
+}
 
-       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++) {
@@ -1304,25 +1305,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);
+                       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:
@@ -1332,13 +1387,15 @@ 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]) {
This page took 0.057117 seconds and 4 git commands to generate.