Commit 927c1452 authored by Daniel Golle's avatar Daniel Golle Committed by Richard Weinberger

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: default avatarDaniel Golle <daniel@makrotopia.org>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 762d73cd
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/of.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/major.h> #include <linux/major.h>
#include "ubi.h" #include "ubi.h"
...@@ -1219,43 +1220,43 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev) ...@@ -1219,43 +1220,43 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
return 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 */ if (!of_device_is_compatible(np, "linux,ubi"))
BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64); return;
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", * we are already holding &mtd_table_mutex, but still need
UBI_MAX_DEVICES); * to bump refcount
return -EINVAL; */
} err = __get_mtd_device(mtd);
if (err)
return;
/* Create base sysfs directory and sysfs files */ /* called while holding mtd_table_mutex */
err = class_register(&ubi_class); 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) if (err < 0)
return err; __put_mtd_device(mtd);
}
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", static void ubi_notify_remove(struct mtd_info *mtd)
sizeof(struct ubi_wl_entry), {
0, 0, NULL); /* do nothing for now */
if (!ubi_wl_entry_slab) { }
err = -ENOMEM;
goto out_dev_unreg;
}
err = ubi_debugfs_init(); static struct mtd_notifier ubi_mtd_notifier = {
if (err) .add = ubi_notify_add,
goto out_slab; .remove = ubi_notify_remove,
};
static int __init ubi_init_attach(void)
{
int err, i, k;
/* Attach MTD devices */ /* Attach MTD devices */
for (i = 0; i < mtd_devs; i++) { for (i = 0; i < mtd_devs; i++) {
...@@ -1304,25 +1305,79 @@ static int __init ubi_init(void) ...@@ -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(); err = ubiblock_init();
if (err) { if (err) {
pr_err("UBI error: block: cannot initialize, error %d\n", err); pr_err("UBI error: block: cannot initialize, error %d\n", err);
/* See comment above re-ubi_is_module(). */ /* See comment above re-ubi_is_module(). */
if (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; return 0;
out_detach: out_mtd_notifier:
for (k = 0; k < i; k++) unregister_mtd_user(&ubi_mtd_notifier);
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_slab: out_slab:
kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_wl_entry_slab);
out_dev_unreg: out_dev_unreg:
...@@ -1332,13 +1387,15 @@ static int __init ubi_init(void) ...@@ -1332,13 +1387,15 @@ static int __init ubi_init(void)
pr_err("UBI error: cannot initialize UBI, error %d\n", err); pr_err("UBI error: cannot initialize UBI, error %d\n", err);
return err; return err;
} }
late_initcall(ubi_init); device_initcall(ubi_init);
static void __exit ubi_exit(void) static void __exit ubi_exit(void)
{ {
int i; int i;
ubiblock_exit(); ubiblock_exit();
unregister_mtd_user(&ubi_mtd_notifier);
for (i = 0; i < UBI_MAX_DEVICES; i++) for (i = 0; i < UBI_MAX_DEVICES; i++)
if (ubi_devices[i]) { if (ubi_devices[i]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment