Introduce a generic "protect" operation to the NVMEM framework.
This allows NVMEM providers to expose hardware-specific protection or
locking mechanisms through the character device interface. Existing
read/write operations do not cover this type of state-altering
protection.

Signed-off-by: Oleksij Rempel <o.rem...@pengutronix.de>
---
changes v2:
- rebase against latest nvmem changes
- use  (offset + count > nvmem->size) instead of (offset >= nvmem->size
  || count > nvmem->size - offset)
- remove NVMEM_PROTECT_ENABLE_WRITE and NVMEM_PROTECT_DISABLE_WRITE
  they will be added later as non nvmem specific defines
---
 drivers/nvmem/core.c           | 32 ++++++++++++++++++++++++++++++++
 drivers/nvmem/partition.c      |  7 +++++++
 include/linux/nvmem-provider.h |  2 ++
 3 files changed, 41 insertions(+)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index fd3c39fd8e43..cfe9770a5f1b 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -30,6 +30,8 @@ struct nvmem_device {
                                             const void *val, size_t val_size);
        int                     (*reg_read)(void *ctx, unsigned int reg,
                                            void *val, size_t val_size);
+       int                     (*reg_protect)(void *ctx, unsigned int reg,
+                                              size_t bytes, int prot);
 };
 
 struct nvmem_cell {
@@ -87,9 +89,38 @@ static ssize_t nvmem_cdev_write(struct cdev *cdev, const 
void *buf, size_t count
        return retlen;
 }
 
+static int nvmem_cdev_protect(struct cdev *cdev, size_t count, loff_t offset,
+                             int prot)
+{
+       struct nvmem_device *nvmem;
+
+       nvmem = container_of(cdev, struct nvmem_device, cdev);
+
+       dev_dbg(cdev->dev, "protect ofs: 0x%08llx count: 0x%08zx prot: %d\n",
+               offset, count, prot);
+
+       if (!nvmem->reg_protect) {
+               dev_warn(cdev->dev, "NVMEM device %s does not support protect 
operation\n",
+                        nvmem->name);
+               return -EOPNOTSUPP;
+       }
+
+       if (!count)
+               return 0;
+
+       if (offset + count > nvmem->size) {
+               dev_err(cdev->dev, "protect range out of bounds (ofs: 0x%08llx, 
count 0x%08zx, size 0x%08zx)\n",
+                       offset, count, nvmem->size);
+               return -EINVAL;
+       }
+
+       return nvmem->reg_protect(nvmem->priv, offset, count, prot);
+}
+
 static struct cdev_operations nvmem_chrdev_ops = {
        .read  = nvmem_cdev_read,
        .write  = nvmem_cdev_write,
+       .protect = nvmem_cdev_protect,
 };
 
 static int nvmem_register_cdev(struct nvmem_device *nvmem, const char *name)
@@ -207,6 +238,7 @@ struct nvmem_device *nvmem_register(const struct 
nvmem_config *config)
        nvmem->dev.parent = config->dev;
        nvmem->reg_read = config->reg_read;
        nvmem->reg_write = config->reg_write;
+       nvmem->reg_protect = config->reg_protect;
        np = config->cdev ? cdev_of_node(config->cdev) : config->dev->of_node;
        nvmem->dev.of_node = np;
        nvmem->priv = config->priv;
diff --git a/drivers/nvmem/partition.c b/drivers/nvmem/partition.c
index d1127c1401af..bb6dbad7b5f6 100644
--- a/drivers/nvmem/partition.c
+++ b/drivers/nvmem/partition.c
@@ -18,6 +18,12 @@ static int nvmem_cdev_read(void *ctx, unsigned offset, void 
*buf, size_t bytes)
        return cdev_read(ctx, buf, bytes, offset, 0);
 }
 
+static int nvmem_cdev_protect(void *ctx, unsigned int offset, size_t bytes,
+                             int prot)
+{
+       return cdev_protect(ctx, bytes, offset, prot);
+}
+
 static int nvmem_cells_probe(struct device *dev)
 {
        struct nvmem_config config = {};
@@ -37,6 +43,7 @@ static int nvmem_cells_probe(struct device *dev)
        config.size = cdev->size;
        config.reg_read = nvmem_cdev_read;
        config.reg_write = nvmem_cdev_write;
+       config.reg_protect = nvmem_cdev_protect;
 
        return PTR_ERR_OR_ZERO(nvmem_register(&config));
 }
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index c1765673eb23..4d44468456f0 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -34,6 +34,8 @@ struct nvmem_config {
                                             const void *val, size_t val_size);
        int                     (*reg_read)(void *ctx, unsigned int reg,
                                            void *val, size_t val_size);
+       int                     (*reg_protect)(void *ctx, unsigned int offset,
+                                              size_t bytes, int prot);
        void                    *priv;
        nvmem_cell_post_process_t cell_post_process;
 };
-- 
2.39.5


Reply via email to