Skip to content

Commit

Permalink
mtd: Add support for reading MTD devices via the nvmem API
Browse files Browse the repository at this point in the history
Allow drivers that use the nvmem API to read data stored on MTD devices.
For this the mtd devices are registered as read-only NVMEM providers.
On OF systems only devices that have the 'nvmem-provider' property
are registered, on non-OF system all MTD devices are registered.

Signed-off-by: Alban Bedel <albeu@free.fr>
---
Changelog:
v2: * Moved to the MTD core instead of using notifiers
    * Fixed the Kconfig description
v3: * Rebased on current kernel
    * Moved the code to mtdcore.c and removed the conditional
      compilation as suggested by Boris Brezillon
    * Fixed my name in From and Signed-off-by
    * Only allow root to read from the nvmem sysfs interface
  • Loading branch information
AlbanBedel committed Mar 24, 2018
1 parent b51425e commit 09c0aa2
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/mtd/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
menuconfig MTD
tristate "Memory Technology Device (MTD) support"
imply NVMEM
help
Memory Technology Devices are flash, RAM and similar chips, often
used for solid state file systems on embedded devices. This option
Expand Down
59 changes: 59 additions & 0 deletions drivers/mtd/mtdcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,48 @@ int mtd_pairing_groups(struct mtd_info *mtd)
}
EXPORT_SYMBOL_GPL(mtd_pairing_groups);

static int mtd_nvmem_reg_read(void *priv, unsigned int offset,
void *val, size_t bytes)
{
struct mtd_info *mtd = priv;
size_t retlen;
int err;

err = mtd_read(mtd, offset, bytes, &retlen, val);
if (err && err != -EUCLEAN)
return err;

return retlen == bytes ? 0 : -EIO;
}

static int mtd_nvmem_add(struct mtd_info *mtd)
{
struct nvmem_config config = {};

config.dev = &mtd->dev;
config.owner = THIS_MODULE;
config.reg_read = mtd_nvmem_reg_read;
config.size = mtd->size;
config.word_size = 1;
config.stride = 1;
config.read_only = true;
config.root_only = true;
config.priv = mtd;

mtd->nvmem = nvmem_register(&config);
if (IS_ERR(mtd->nvmem)) {
/* Just ignore if there is no NVMEM support in the kernel */
if (PTR_ERR(mtd->nvmem) == -ENOSYS) {
mtd->nvmem = NULL;
} else {
dev_err(&mtd->dev, "Failed to register NVMEM device\n");
return PTR_ERR(mtd->nvmem);
}
}

return 0;
}

static struct dentry *dfs_dir_mtd;

/**
Expand Down Expand Up @@ -560,6 +602,11 @@ int add_mtd_device(struct mtd_info *mtd)
if (error)
goto fail_added;

/* Add the nvmem provider */
error = mtd_nvmem_add(mtd);
if (error)
goto fail_nvmem_add;

if (!IS_ERR_OR_NULL(dfs_dir_mtd)) {
mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd);
if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) {
Expand All @@ -585,6 +632,8 @@ int add_mtd_device(struct mtd_info *mtd)
__module_get(THIS_MODULE);
return 0;

fail_nvmem_add:
device_unregister(&mtd->dev);
fail_added:
of_node_put(mtd_get_of_node(mtd));
idr_remove(&mtd_idr, i);
Expand Down Expand Up @@ -627,6 +676,16 @@ int del_mtd_device(struct mtd_info *mtd)
mtd->index, mtd->name, mtd->usecount);
ret = -EBUSY;
} else {
/* Try to remove the NVMEM provider */
if (mtd->nvmem) {
ret = nvmem_unregister(mtd->nvmem);
if (ret) {
dev_err(&mtd->dev,
"Failed to unregister NVMEM device\n");
goto out_error;
}
}

device_unregister(&mtd->dev);

idr_remove(&mtd_idr, mtd->index);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mtd/mtd.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/notifier.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/nvmem-provider.h>

#include <mtd/mtd-abi.h>

Expand Down Expand Up @@ -352,6 +353,7 @@ struct mtd_info {
struct device dev;
int usecount;
struct mtd_debug_info dbg;
struct nvmem_device *nvmem;
};

int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
Expand Down

0 comments on commit 09c0aa2

Please sign in to comment.