[RFC PATCH] nvmem: core: add sysfs cell write support

From: Marco Felsch
Date: Thu Feb 15 2024 - 16:14:23 EST


Add the sysfs cell write support to make it possible to write to exposed
cells from sysfs as well e.g. for device provisioning.

Signed-off-by: Marco Felsch <m.felsch@xxxxxxxxxxxxxx>
---
Hi,

the purpose of this patch is to make the NVMEM cells exposed via the
testing ABI sysfs writeable, to allow changes during devie life-time.

Regards,
Marco

drivers/nvmem/core.c | 40 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 980123fb4dde..5a497188cfea 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -336,6 +336,40 @@ static ssize_t nvmem_cell_attr_read(struct file *filp, struct kobject *kobj,
return read_len;
}

+static ssize_t nvmem_cell_attr_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ struct nvmem_cell_entry *entry;
+ struct nvmem_cell *cell;
+ int ret;
+
+ entry = attr->private;
+
+ if (!entry->nvmem->reg_write)
+ return -EPERM;
+
+ if (pos >= entry->bytes)
+ return -EFBIG;
+
+ if (pos + count > entry->bytes)
+ count = entry->bytes - pos;
+
+ cell = nvmem_create_cell(entry, entry->name, 0);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ if (!cell)
+ return -EINVAL;
+
+ ret = nvmem_cell_write(cell, buf, count);
+
+ kfree_const(cell->id);
+ kfree(cell);
+
+ return ret;
+}
+
/* default read/write permissions */
static struct bin_attribute bin_attr_rw_nvmem = {
.attr = {
@@ -432,6 +466,7 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
struct bin_attribute **cells_attrs, *attrs;
struct nvmem_cell_entry *entry;
unsigned int ncells = 0, i = 0;
+ umode_t mode;
int ret = 0;

mutex_lock(&nvmem_mutex);
@@ -456,15 +491,18 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
goto unlock_mutex;
}

+ mode = nvmem_bin_attr_get_umode(nvmem);
+
/* Initialize each attribute to take the name and size of the cell */
list_for_each_entry(entry, &nvmem->cells, node) {
sysfs_bin_attr_init(&attrs[i]);
attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL,
"%s@%x", entry->name,
entry->offset);
- attrs[i].attr.mode = 0444;
+ attrs[i].attr.mode = mode;
attrs[i].size = entry->bytes;
attrs[i].read = &nvmem_cell_attr_read;
+ attrs[i].write = &nvmem_cell_attr_write;
attrs[i].private = entry;
if (!attrs[i].attr.name) {
ret = -ENOMEM;
--
2.39.2