linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vadym Kochan <vadym.kochan@plvision.eu>
To: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
Cc: Robert Marko <robert.marko@sartura.hr>,
	Vadym Kochan <vadym.kochan@plvision.eu>
Subject: [PATCH v2 1/3] nvmem: core: introduce cells parser
Date: Tue,  8 Jun 2021 22:03:25 +0300	[thread overview]
Message-ID: <20210608190327.22071-2-vadym.kochan@plvision.eu> (raw)
In-Reply-To: <20210608190327.22071-1-vadym.kochan@plvision.eu>

Current implementation does not allow to register cells for already
registered nvmem device and requires that this should be done before. But
there might a driver which needs to parse the nvmem device and after
register a cells table.

Introduce nvmem_parser API which allows to register cells parser which
is called during nvmem device registration. During this stage the parser
can read the nvmem device and register the cells table.

Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
---
v2:
    1) Added nvmem_parser_data so parser implementation
       should fill it with cells table and lookups which
       will be registered by core.c after cells_parse was
       succeed.

    2) Removed cells_remove callback from nvmem_parser_config which
       is not needed because cells table & lookups are
       registered/unregistered automatically by core.

    3) Use new device property to read cells parser name during nvmem
       registration. Removed of_node usage.

    4) parser's module refcount is incremented/decremented on each parser
       bind/unbind to nvmem device.

 drivers/nvmem/core.c           | 178 +++++++++++++++++++++++++++++++++
 include/linux/nvmem-provider.h |  31 ++++++
 2 files changed, 209 insertions(+)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index bca671ff4e54..648373ced6d4 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -39,6 +39,7 @@ struct nvmem_device {
 	nvmem_reg_read_t	reg_read;
 	nvmem_reg_write_t	reg_write;
 	struct gpio_desc	*wp_gpio;
+	struct nvmem_parser_data *parser_data;
 	void *priv;
 };
 
@@ -57,6 +58,13 @@ struct nvmem_cell {
 	struct list_head	node;
 };
 
+struct nvmem_parser {
+	struct list_head	head;
+	nvmem_parse_t		cells_parse;
+	const char		*name;
+	struct module		*owner;
+};
+
 static DEFINE_MUTEX(nvmem_mutex);
 static DEFINE_IDA(nvmem_ida);
 
@@ -66,6 +74,9 @@ static LIST_HEAD(nvmem_cell_tables);
 static DEFINE_MUTEX(nvmem_lookup_mutex);
 static LIST_HEAD(nvmem_lookup_list);
 
+static DEFINE_MUTEX(nvmem_parser_mutex);
+static LIST_HEAD(nvmem_parser_list);
+
 static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
 
 static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
@@ -418,6 +429,118 @@ static struct bus_type nvmem_bus_type = {
 	.name		= "nvmem",
 };
 
+static struct nvmem_parser *__nvmem_parser_get(const char *name)
+{
+	struct nvmem_parser *tmp, *parser = NULL;
+
+	list_for_each_entry(tmp, &nvmem_parser_list, head) {
+		if (strcmp(name, tmp->name) == 0) {
+			parser = tmp;
+			break;
+		}
+	}
+
+	if (!parser)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (!try_module_get(parser->owner)) {
+		pr_err("could not increase module refcount for parser %s\n",
+		       parser->name);
+		return ERR_PTR(-EINVAL);
+
+	}
+
+	return parser;
+}
+
+static void nvmem_parser_put(const struct nvmem_parser *parser)
+{
+	module_put(parser->owner);
+}
+
+static int nvmem_parser_bind(struct nvmem_device *nvmem, const char *name)
+{
+	struct nvmem_parser_data *data;
+	struct nvmem_parser *parser;
+	int err;
+
+	mutex_lock(&nvmem_parser_mutex);
+
+	parser = __nvmem_parser_get(name);
+	err = PTR_ERR_OR_ZERO(parser);
+	if (!err) {
+		data = kzalloc(sizeof(*data), GFP_KERNEL);
+		if (data) {
+			data->parser = parser;
+			nvmem->parser_data = data;
+		} else {
+			nvmem_parser_put(parser);
+			err = -ENOMEM;
+		}
+	}
+
+	mutex_unlock(&nvmem_parser_mutex);
+
+	return err;
+}
+
+static void nvmem_parser_unbind(const struct nvmem_device *nvmem)
+{
+	struct nvmem_parser_data *data = nvmem->parser_data;
+
+	if (data->table.cells) {
+		nvmem_del_cell_table(&data->table);
+		kfree(data->table.cells);
+	}
+	if (data->lookup) {
+		nvmem_del_cell_lookups(data->lookup, data->nlookups);
+		kfree(data->lookup);
+	}
+
+	nvmem_parser_put(data->parser);
+}
+
+static void nvmem_parser_data_register(struct nvmem_device *nvmem,
+				       struct nvmem_parser_data *data)
+{
+	if (data->table.cells) {
+		if (!data->table.nvmem_name)
+			data->table.nvmem_name = nvmem_dev_name(nvmem);
+
+		nvmem_add_cell_table(&data->table);
+	}
+
+	if (data->lookup) {
+		struct nvmem_cell_lookup *lookup = &data->lookup[0];
+		int i = 0;
+
+		for (i = 0; i < data->nlookups; i++, lookup++) {
+			if (!lookup->nvmem_name)
+				lookup->nvmem_name = nvmem_dev_name(nvmem);
+
+			if (!lookup->dev_id)
+				lookup->dev_id = data->parser->name;
+		}
+
+		nvmem_add_cell_lookups(data->lookup, data->nlookups);
+	}
+}
+
+static void nvmem_cells_parse(struct nvmem_device *nvmem)
+{
+	struct nvmem_parser_data *data = nvmem->parser_data;
+	struct nvmem_parser *parser = data->parser;
+	int err;
+
+	mutex_lock(&nvmem_parser_mutex);
+
+	err = parser->cells_parse(nvmem, data);
+	if (!err)
+		nvmem_parser_data_register(nvmem, data);
+
+	mutex_unlock(&nvmem_parser_mutex);
+}
+
 static void nvmem_cell_drop(struct nvmem_cell *cell)
 {
 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
@@ -435,6 +558,9 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
 
 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
 		nvmem_cell_drop(cell);
+
+	if (nvmem->parser_data)
+		nvmem_parser_unbind(nvmem);
 }
 
 static void nvmem_cell_add(struct nvmem_cell *cell)
@@ -739,6 +865,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
 struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 {
 	struct nvmem_device *nvmem;
+	const char *parser_name;
 	int rval;
 
 	if (!config->dev)
@@ -809,6 +936,16 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 	nvmem->read_only = device_property_present(config->dev, "read-only") ||
 			   config->read_only || !nvmem->reg_write;
 
+	if (!device_property_read_string(config->dev, "nvmem-cell-parser-name",
+					 &parser_name)) {
+		rval = nvmem_parser_bind(nvmem, parser_name);
+		if (rval) {
+			ida_free(&nvmem_ida, nvmem->id);
+			kfree(nvmem);
+			return ERR_PTR(rval);
+		}
+	}
+
 #ifdef CONFIG_NVMEM_SYSFS
 	nvmem->dev.groups = nvmem_dev_groups;
 #endif
@@ -837,6 +974,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 			goto err_teardown_compat;
 	}
 
+	if (nvmem->parser_data)
+		nvmem_cells_parse(nvmem);
+
 	rval = nvmem_add_cells_from_table(nvmem);
 	if (rval)
 		goto err_remove_cells;
@@ -857,6 +997,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 err_device_del:
 	device_del(&nvmem->dev);
 err_put_device:
+	if (nvmem->parser_data)
+		nvmem_parser_unbind(nvmem);
 	put_device(&nvmem->dev);
 
 	return ERR_PTR(rval);
@@ -1891,6 +2033,42 @@ const char *nvmem_dev_name(struct nvmem_device *nvmem)
 }
 EXPORT_SYMBOL_GPL(nvmem_dev_name);
 
+struct nvmem_parser *
+nvmem_parser_register(const struct nvmem_parser_config *config)
+{
+	struct nvmem_parser *parser;
+
+	if (!config->cells_parse)
+		return ERR_PTR(-EINVAL);
+
+	if (!config->name)
+		return ERR_PTR(-EINVAL);
+
+	parser = kzalloc(sizeof(*parser), GFP_KERNEL);
+	if (!parser)
+		return ERR_PTR(-ENOMEM);
+
+	parser->cells_parse = config->cells_parse;
+	parser->owner = config->owner;
+	parser->name = config->name;
+
+	mutex_lock(&nvmem_parser_mutex);
+	list_add(&parser->head, &nvmem_parser_list);
+	mutex_unlock(&nvmem_parser_mutex);
+
+	return parser;
+}
+EXPORT_SYMBOL(nvmem_parser_register);
+
+void nvmem_parser_unregister(struct nvmem_parser *parser)
+{
+	mutex_lock(&nvmem_parser_mutex);
+	list_del(&parser->head);
+	kfree(parser);
+	mutex_unlock(&nvmem_parser_mutex);
+}
+EXPORT_SYMBOL(nvmem_parser_unregister);
+
 static int __init nvmem_init(void)
 {
 	return bus_register(&nvmem_bus_type);
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index e162b757b6d5..447241706554 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -15,10 +15,15 @@
 
 struct nvmem_device;
 struct nvmem_cell_info;
+struct nvmem_cell_table;
+struct nvmem_parser_data;
+
 typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
 				void *val, size_t bytes);
 typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
 				 void *val, size_t bytes);
+typedef int (*nvmem_parse_t)(struct nvmem_device *nvmem,
+			     struct nvmem_parser_data *data);
 
 enum nvmem_type {
 	NVMEM_TYPE_UNKNOWN = 0,
@@ -117,6 +122,19 @@ struct nvmem_cell_table {
 	struct list_head	node;
 };
 
+struct nvmem_parser_config {
+	const char	*name;
+	nvmem_parse_t	cells_parse;
+	struct module	*owner;
+};
+
+struct nvmem_parser_data {
+	struct nvmem_cell_table		table;
+	struct nvmem_cell_lookup	*lookup;
+	int				nlookups;
+	struct nvmem_parser		*parser;
+};
+
 #if IS_ENABLED(CONFIG_NVMEM)
 
 struct nvmem_device *nvmem_register(const struct nvmem_config *cfg);
@@ -130,6 +148,11 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem);
 void nvmem_add_cell_table(struct nvmem_cell_table *table);
 void nvmem_del_cell_table(struct nvmem_cell_table *table);
 
+struct nvmem_parser *
+nvmem_parser_register(const struct nvmem_parser_config *config);
+
+void nvmem_parser_unregister(struct nvmem_parser *parser);
+
 #else
 
 static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c)
@@ -154,5 +177,13 @@ devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
 static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {}
 static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {}
 
+static inline struct nvmem_parser *
+nvmem_parser_register(const struct nvmem_parser_config *config)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void nvmem_parser_unregister(struct nvmem_parser *parser) {}
+
 #endif /* CONFIG_NVMEM */
 #endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */
-- 
2.17.1


  reply	other threads:[~2021-06-08 19:19 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-08 19:03 [PATCH v2 0/3] nvmem: add ONIE NVMEM cells parser Vadym Kochan
2021-06-08 19:03 ` Vadym Kochan [this message]
2021-06-08 22:49   ` [PATCH v2 1/3] nvmem: core: introduce " kernel test robot
2021-06-09  3:05   ` kernel test robot
2021-06-14 10:44   ` Srinivas Kandagatla
2021-06-16 12:33     ` Vadym Kochan
2021-06-21 11:00       ` Srinivas Kandagatla
2021-09-08  9:38         ` Vadym Kochan
2021-09-13 14:19           ` Srinivas Kandagatla
2021-09-20 10:24             ` Vadym Kochan
2021-09-20 10:36               ` Srinivas Kandagatla
2021-09-20 11:25                 ` Vadym Kochan
2021-09-20 11:32                   ` Srinivas Kandagatla
2021-09-20 12:29                     ` Vadym Kochan
2021-09-20 12:34                       ` Srinivas Kandagatla
2021-09-20 13:29                         ` Vadym Kochan
2021-09-20 13:40                           ` Srinivas Kandagatla
2021-09-21  5:50                             ` John Thomson
2021-09-27  7:50                               ` Vadym Kochan
2021-09-27 10:12                                 ` Srinivas Kandagatla
2021-09-28 13:31                                   ` Vadym Kochan
2021-09-28 13:51                                     ` Srinivas Kandagatla
2021-09-28 14:11                                       ` Vadym Kochan
2021-09-28 14:39                                         ` Srinivas Kandagatla
2021-09-27 10:12                               ` Srinivas Kandagatla
2021-09-27 12:38                                 ` John Thomson
2021-09-08  9:44     ` Vadym Kochan
2021-06-08 19:03 ` [PATCH v2 2/3] dt-bindings: nvmem: document nvmem-cells-parser-name property Vadym Kochan
2021-06-18 20:59   ` Rob Herring
2021-06-08 19:03 ` [PATCH v2 3/3] nvmem: add ONIE nvmem cells parser Vadym Kochan
2021-08-06 15:39   ` Jan Lübbe
2021-09-08  9:56     ` Vadym Kochan
2021-09-12 21:06       ` John Thomson
2021-09-13 14:20         ` Srinivas Kandagatla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210608190327.22071-2-vadym.kochan@plvision.eu \
    --to=vadym.kochan@plvision.eu \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robert.marko@sartura.hr \
    --cc=robh+dt@kernel.org \
    --cc=srinivas.kandagatla@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).