linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] nvmem: add ONIE NVMEM cells provider
@ 2020-05-29 23:04 Vadym Kochan
  2020-05-29 23:04 ` [PATCH v2 1/2] nvmem: core: allow to register cells for existing device Vadym Kochan
  2020-05-29 23:04 ` [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support Vadym Kochan
  0 siblings, 2 replies; 10+ messages in thread
From: Vadym Kochan @ 2020-05-29 23:04 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-kernel, Greg Kroah-Hartman
  Cc: Taras Chornyi, Vadym Kochan

This series adds cells provider for the ONIE TLV attributes which are
stored on NVMEM device. It adds possibility to read the mac address (and
other info) by other drivers.

Driver needs to register NVMEM cells table for already registered
NVMEM device, this requires additional change to the core logic because
current logic only allows to add additional cells only before nvmem
device registration.

v2:
    1) Fixed wrong memcmp comparison

Vadym Kochan (2):
  nvmem: core: allow to register cells for existing device
  nvmem: add ONIE NVMEM cells support

 drivers/nvmem/Kconfig      |   9 +
 drivers/nvmem/Makefile     |   3 +
 drivers/nvmem/core.c       |  59 ++++---
 drivers/nvmem/onie-cells.c | 332 +++++++++++++++++++++++++++++++++++++
 4 files changed, 381 insertions(+), 22 deletions(-)
 create mode 100644 drivers/nvmem/onie-cells.c

-- 
2.17.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/2] nvmem: core: allow to register cells for existing device
  2020-05-29 23:04 [PATCH v2 0/2] nvmem: add ONIE NVMEM cells provider Vadym Kochan
@ 2020-05-29 23:04 ` Vadym Kochan
  2020-05-29 23:04 ` [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support Vadym Kochan
  1 sibling, 0 replies; 10+ messages in thread
From: Vadym Kochan @ 2020-05-29 23:04 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-kernel, Greg Kroah-Hartman
  Cc: Taras Chornyi, Vadym Kochan

Current implementation does not allow to register nvmem cells for
existing device and requires that this will be done before device is
registered.

But there might a driver which provides only cells info which needs to
be added for already registered nvmem device.

Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
---
 drivers/nvmem/core.c | 59 +++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 05c6ae4b0b97..39c9df9ae9a0 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -482,35 +482,43 @@ int nvmem_unregister_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
 
-static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
+static int __nvmem_add_cells_from_table(struct nvmem_device *nvmem,
+					struct nvmem_cell_table *table)
 {
 	const struct nvmem_cell_info *info;
-	struct nvmem_cell_table *table;
 	struct nvmem_cell *cell;
-	int rval = 0, i;
+	int err, i;
+
+	for (i = 0; i < table->ncells; i++) {
+		info = &table->cells[i];
+
+		cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+		if (!cell)
+			return -ENOMEM;
+
+		err = nvmem_cell_info_to_nvmem_cell(nvmem, info, cell);
+		if (err) {
+			kfree(cell);
+			return err;
+		}
+
+		nvmem_cell_add(cell);
+	}
+
+	return 0;
+}
+
+static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
+{
+	struct nvmem_cell_table *table;
+	int rval = 0;
 
 	mutex_lock(&nvmem_cell_mutex);
 	list_for_each_entry(table, &nvmem_cell_tables, node) {
 		if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
-			for (i = 0; i < table->ncells; i++) {
-				info = &table->cells[i];
-
-				cell = kzalloc(sizeof(*cell), GFP_KERNEL);
-				if (!cell) {
-					rval = -ENOMEM;
-					goto out;
-				}
-
-				rval = nvmem_cell_info_to_nvmem_cell(nvmem,
-								     info,
-								     cell);
-				if (rval) {
-					kfree(cell);
-					goto out;
-				}
-
-				nvmem_cell_add(cell);
-			}
+			rval = __nvmem_add_cells_from_table(nvmem, table);
+			if (rval)
+				goto out;
 		}
 	}
 
@@ -1560,6 +1568,13 @@ EXPORT_SYMBOL_GPL(nvmem_device_write);
  */
 void nvmem_add_cell_table(struct nvmem_cell_table *table)
 {
+	const char *dev_name = table->nvmem_name;
+	struct nvmem_device *nvmem;
+
+	nvmem = __nvmem_device_get((void *)dev_name, device_match_name);
+	if (nvmem)
+		__nvmem_add_cells_from_table(nvmem, table);
+
 	mutex_lock(&nvmem_cell_mutex);
 	list_add_tail(&table->node, &nvmem_cell_tables);
 	mutex_unlock(&nvmem_cell_mutex);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-05-29 23:04 [PATCH v2 0/2] nvmem: add ONIE NVMEM cells provider Vadym Kochan
  2020-05-29 23:04 ` [PATCH v2 1/2] nvmem: core: allow to register cells for existing device Vadym Kochan
@ 2020-05-29 23:04 ` Vadym Kochan
  2020-06-01  8:50   ` Srinivas Kandagatla
  1 sibling, 1 reply; 10+ messages in thread
From: Vadym Kochan @ 2020-05-29 23:04 UTC (permalink / raw)
  To: Srinivas Kandagatla, linux-kernel, Greg Kroah-Hartman
  Cc: Taras Chornyi, Vadym Kochan

ONIE is a small operating system, pre-installed on bare metal network
switches, that provides an environment for automated provisioning.

This system requires that NVMEM (EEPROM) device holds various system
information (mac address, platform name, etc) in a special TLV layout.

The driver registers ONIE TLV attributes as NVMEM cells which can be
accessed by other platform driver. Also it allows to use
of_get_mac_address() to retrieve mac address for the netdev.

Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
---
 drivers/nvmem/Kconfig      |   9 +
 drivers/nvmem/Makefile     |   3 +
 drivers/nvmem/onie-cells.c | 332 +++++++++++++++++++++++++++++++++++++
 3 files changed, 344 insertions(+)
 create mode 100644 drivers/nvmem/onie-cells.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index d7b7f6d688e7..dd9298487992 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -273,4 +273,13 @@ config SPRD_EFUSE
 	  This driver can also be built as a module. If so, the module
 	  will be called nvmem-sprd-efuse.
 
+config NVMEM_ONIE_CELLS
+	tristate "ONIE TLV cells support"
+	help
+	  This is a driver to provide cells from ONIE TLV structure stored
+	  on NVME device.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called nvmem-onie-cells.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index a7c377218341..2199784a489f 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -55,3 +55,6 @@ obj-$(CONFIG_NVMEM_ZYNQMP)	+= nvmem_zynqmp_nvmem.o
 nvmem_zynqmp_nvmem-y		:= zynqmp_nvmem.o
 obj-$(CONFIG_SPRD_EFUSE)	+= nvmem_sprd_efuse.o
 nvmem_sprd_efuse-y		:= sprd-efuse.o
+
+obj-$(CONFIG_NVMEM_ONIE_CELLS)	+= nvmem-onie-cells.o
+nvmem-onie-cells-y		:= onie-cells.o
diff --git a/drivers/nvmem/onie-cells.c b/drivers/nvmem/onie-cells.c
new file mode 100644
index 000000000000..1e8b4b8d1c0d
--- /dev/null
+++ b/drivers/nvmem/onie-cells.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ONIE NVMEM cells provider
+ *
+ * Author: Vadym Kochan <vadym.kochan@plvision.eu>
+ */
+
+#define ONIE_NVMEM_DRVNAME	"onie-nvmem-cells"
+
+#define pr_fmt(fmt) ONIE_NVMEM_DRVNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
+
+#define ONIE_NVMEM_TLV_MAX_LEN	2048
+
+#define ONIE_NVMEM_HDR_ID	"TlvInfo"
+
+struct onie_nvmem_hdr {
+	u8 id[8];
+	u8 version;
+	__be16 data_len;
+} __packed;
+
+struct onie_nvmem_tlv {
+	u8 type;
+	u8 len;
+	u8 val[0];
+} __packed;
+
+struct onie_nvmem_attr {
+	struct list_head head;
+	const char *name;
+	unsigned int offset;
+	unsigned int len;
+};
+
+struct onie_nvmem {
+	struct nvmem_device *nvmem;
+	unsigned int attr_count;
+	struct list_head attrs;
+
+	struct nvmem_cell_lookup *cell_lookup;
+	struct nvmem_cell_table cell_tbl;
+};
+
+static bool onie_nvmem_hdr_is_valid(struct onie_nvmem_hdr *hdr)
+{
+	if (memcmp(hdr->id, ONIE_NVMEM_HDR_ID, sizeof(hdr->id)) != 0)
+		return false;
+	if (hdr->version != 0x1)
+		return false;
+
+	return true;
+}
+
+static void onie_nvmem_attrs_free(struct onie_nvmem *onie)
+{
+	struct onie_nvmem_attr *attr, *tmp;
+
+	list_for_each_entry_safe(attr, tmp, &onie->attrs, head) {
+		list_del(&attr->head);
+		kfree(attr);
+	}
+}
+
+static const char *onie_nvmem_attr_name(u8 type)
+{
+	switch (type) {
+	case 0x21: return "product-name";
+	case 0x22: return "part-number";
+	case 0x23: return "serial-number";
+	case 0x24: return "mac-address";
+	case 0x25: return "manufacture-date";
+	case 0x26: return "device-version";
+	case 0x27: return "label-revision";
+	case 0x28: return "platforn-name";
+	case 0x29: return "onie-version";
+	case 0x2A: return "num-macs";
+	case 0x2B: return "manufacturer";
+	case 0x2C: return "country-code";
+	case 0x2D: return "vendor";
+	case 0x2E: return "diag-version";
+	case 0x2F: return "service-tag";
+	case 0xFD: return "vendor-extension";
+	case 0xFE: return "crc32";
+
+	default: return "unknown";
+	}
+}
+
+static int onie_nvmem_tlv_parse(struct onie_nvmem *onie, u8 *data, u16 len)
+{
+	unsigned int hlen = sizeof(struct onie_nvmem_hdr);
+	unsigned int offset = 0;
+	int err;
+
+	while (offset < len) {
+		struct onie_nvmem_attr *attr;
+		struct onie_nvmem_tlv *tlv;
+
+		tlv = (struct onie_nvmem_tlv *)(data + offset);
+
+		if (offset + tlv->len >= len) {
+			struct nvmem_device *nvmem = onie->nvmem;
+
+			pr_err("%s: TLV len is too big(0x%x) at 0x%x\n",
+			       nvmem_dev_name(nvmem), tlv->len, hlen + offset);
+
+			/* return success in case something was parsed */
+			return 0;
+		}
+
+		attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+		if (!attr) {
+			err = -ENOMEM;
+			goto err_attr_alloc;
+		}
+
+		attr->name = onie_nvmem_attr_name(tlv->type);
+		/* skip 'type' and 'len' */
+		attr->offset = hlen + offset + 2;
+		attr->len = tlv->len;
+
+		list_add(&attr->head, &onie->attrs);
+		onie->attr_count++;
+
+		offset += sizeof(*tlv) + tlv->len;
+	}
+
+	return 0;
+
+err_attr_alloc:
+	onie_nvmem_attrs_free(onie);
+
+	return err;
+}
+
+static int onie_nvmem_decode(struct onie_nvmem *onie)
+{
+	struct nvmem_device *nvmem = onie->nvmem;
+	struct onie_nvmem_hdr hdr;
+	u8 *data;
+	u16 len;
+	int ret;
+
+	ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr);
+	if (ret < 0)
+		return ret;
+
+	if (!onie_nvmem_hdr_is_valid(&hdr)) {
+		pr_err("%s: invalid ONIE TLV header\n", nvmem_dev_name(nvmem));
+		ret = -EINVAL;
+		goto err_invalid;
+	}
+
+	len = be16_to_cpu(hdr.data_len);
+
+	if (len > ONIE_NVMEM_TLV_MAX_LEN)
+		len = ONIE_NVMEM_TLV_MAX_LEN;
+
+	data = kmalloc(len, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err_kmalloc;
+	}
+
+	ret = nvmem_device_read(nvmem, sizeof(hdr), len, data);
+	if (ret < 0)
+		goto err_data_read;
+
+	ret = onie_nvmem_tlv_parse(onie, data, len);
+	if (ret)
+		goto err_info_parse;
+
+	kfree(data);
+
+	return 0;
+
+err_info_parse:
+err_data_read:
+	kfree(data);
+err_kmalloc:
+err_invalid:
+	return ret;
+}
+
+static int onie_nvmem_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct nvmem_cell_info *cells;
+	struct onie_nvmem_attr *attr;
+	struct nvmem_device *nvmem;
+	struct onie_nvmem *onie;
+	unsigned int ncells = 0;
+	int err;
+
+	nvmem = of_nvmem_device_get(np, NULL);
+	if (IS_ERR(nvmem))
+		return PTR_ERR(nvmem);
+
+	onie = kmalloc(sizeof(*onie), GFP_KERNEL);
+	if (!onie) {
+		err = -ENOMEM;
+		goto err_nvmem_alloc;
+	}
+
+	INIT_LIST_HEAD(&onie->attrs);
+	onie->attr_count = 0;
+	onie->nvmem = nvmem;
+
+	err = onie_nvmem_decode(onie);
+	if (err)
+		goto err_nvmem_decode;
+
+	if (!onie->attr_count) {
+		pr_err("%s: has no ONIE attributes\n", nvmem_dev_name(nvmem));
+		err = -EINVAL;
+		goto err_no_attrs;
+	}
+
+	cells = kmalloc_array(onie->attr_count, sizeof(*cells), GFP_KERNEL);
+	if (!cells) {
+		err = -ENOMEM;
+		goto err_cells_alloc;
+	}
+
+	onie->cell_lookup = kmalloc_array(onie->attr_count,
+					  sizeof(struct nvmem_cell_lookup),
+					  GFP_KERNEL);
+	if (!onie->cell_lookup) {
+		err = -ENOMEM;
+		goto err_lookup_alloc;
+	}
+
+	list_for_each_entry(attr, &onie->attrs, head) {
+		struct nvmem_cell_lookup *lookup;
+		struct nvmem_cell_info *cell;
+
+		cell = &cells[ncells];
+
+		lookup = &onie->cell_lookup[ncells];
+		lookup->con_id = NULL;
+
+		cell->offset = attr->offset;
+		cell->name = attr->name;
+		cell->bytes = attr->len;
+		cell->bit_offset = 0;
+		cell->nbits = 0;
+
+		lookup->nvmem_name = nvmem_dev_name(onie->nvmem);
+		lookup->dev_id = dev_name(dev);
+		lookup->cell_name = cell->name;
+		lookup->con_id = cell->name;
+
+		ncells++;
+	}
+
+	onie->cell_tbl.nvmem_name = nvmem_dev_name(onie->nvmem);
+	onie->cell_tbl.ncells = ncells;
+	onie->cell_tbl.cells = cells;
+
+	nvmem_add_cell_table(&onie->cell_tbl);
+	nvmem_add_cell_lookups(onie->cell_lookup, ncells);
+
+	dev_set_drvdata(dev, onie);
+
+	onie_nvmem_attrs_free(onie);
+
+	nvmem_device_put(nvmem);
+
+	return 0;
+
+err_lookup_alloc:
+	kfree(onie->cell_tbl.cells);
+err_cells_alloc:
+	onie_nvmem_attrs_free(onie);
+err_no_attrs:
+err_nvmem_decode:
+	kfree(onie);
+err_nvmem_alloc:
+	nvmem_device_put(nvmem);
+
+	return err;
+}
+
+static int onie_nvmem_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct onie_nvmem *onie;
+
+	onie = dev_get_drvdata(dev);
+
+	nvmem_del_cell_lookups(onie->cell_lookup, onie->attr_count);
+	nvmem_del_cell_table(&onie->cell_tbl);
+
+	kfree(onie->cell_tbl.cells);
+	kfree(onie->cell_lookup);
+	kfree(onie);
+
+	return 0;
+}
+
+static const struct of_device_id onie_nvmem_match[] = {
+	{
+		.compatible = "onie-nvmem-cells",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, onie_nvmem_match);
+
+static struct platform_driver onie_nvmem_driver = {
+	.probe = onie_nvmem_probe,
+	.remove = onie_nvmem_remove,
+	.driver = {
+		.name = ONIE_NVMEM_DRVNAME,
+		.of_match_table = onie_nvmem_match,
+	},
+};
+module_platform_driver(onie_nvmem_driver);
+
+MODULE_AUTHOR("Vadym Kochan <vadym.kochan@plvision.eu>");
+MODULE_DESCRIPTION("ONIE NVMEM cells driver");
+MODULE_LICENSE("GPL");
-- 
2.17.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-05-29 23:04 ` [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support Vadym Kochan
@ 2020-06-01  8:50   ` Srinivas Kandagatla
  2020-06-01  9:03     ` Vadym Kochan
  0 siblings, 1 reply; 10+ messages in thread
From: Srinivas Kandagatla @ 2020-06-01  8:50 UTC (permalink / raw)
  To: Vadym Kochan, linux-kernel, Greg Kroah-Hartman; +Cc: Taras Chornyi



On 30/05/2020 00:04, Vadym Kochan wrote:
> ONIE is a small operating system, pre-installed on bare metal network
> switches, that provides an environment for automated provisioning.
> 
> This system requires that NVMEM (EEPROM) device holds various system
> information (mac address, platform name, etc) in a special TLV layout.
> 
> The driver registers ONIE TLV attributes as NVMEM cells which can be
> accessed by other platform driver. Also it allows to use
> of_get_mac_address() to retrieve mac address for the netdev.
> 
> Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
> ---
>   drivers/nvmem/Kconfig      |   9 +
>   drivers/nvmem/Makefile     |   3 +
>   drivers/nvmem/onie-cells.c | 332 +++++++++++++++++++++++++++++++++++++

Is there a reason why Device tree bindings are missing for this driver?



>   3 files changed, 344 insertions(+)
>   create mode 100644 drivers/nvmem/onie-cells.c
> 
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index d7b7f6d688e7..dd9298487992 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -273,4 +273,13 @@ config SPRD_EFUSE
>   	  This driver can also be built as a module. If so, the module
>   	  will be called nvmem-sprd-efuse.
>   
> +config NVMEM_ONIE_CELLS
> +	tristate "ONIE TLV cells support"
> +	help
> +	  This is a driver to provide cells from ONIE TLV structure stored
> +	  on NVME device.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called nvmem-onie-cells.
> +
>   endif
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index a7c377218341..2199784a489f 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -55,3 +55,6 @@ obj-$(CONFIG_NVMEM_ZYNQMP)	+= nvmem_zynqmp_nvmem.o
>   nvmem_zynqmp_nvmem-y		:= zynqmp_nvmem.o
>   obj-$(CONFIG_SPRD_EFUSE)	+= nvmem_sprd_efuse.o
>   nvmem_sprd_efuse-y		:= sprd-efuse.o
> +
> +obj-$(CONFIG_NVMEM_ONIE_CELLS)	+= nvmem-onie-cells.o
> +nvmem-onie-cells-y		:= onie-cells.o
> diff --git a/drivers/nvmem/onie-cells.c b/drivers/nvmem/onie-cells.c
> new file mode 100644
> index 000000000000..1e8b4b8d1c0d
> --- /dev/null
> +++ b/drivers/nvmem/onie-cells.c
> @@ -0,0 +1,332 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * ONIE NVMEM cells provider
> + *
> + * Author: Vadym Kochan <vadym.kochan@plvision.eu>
> + */
> +
> +#define ONIE_NVMEM_DRVNAME	"onie-nvmem-cells"
> +
> +#define pr_fmt(fmt) ONIE_NVMEM_DRVNAME ": " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/nvmem-provider.h>
> +
> +#define ONIE_NVMEM_TLV_MAX_LEN	2048
> +
> +#define ONIE_NVMEM_HDR_ID	"TlvInfo"
> +

...

> +
> +static int onie_nvmem_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct nvmem_cell_info *cells;
> +	struct onie_nvmem_attr *attr;
> +	struct nvmem_device *nvmem;
> +	struct onie_nvmem *onie;
> +	unsigned int ncells = 0;
> +	int err;
> +
> +	nvmem = of_nvmem_device_get(np, NULL);
> +	if (IS_ERR(nvmem))
> +		return PTR_ERR(nvmem);
> +
TBH, this looks completely incorrect way to do this and misuse of nvmem 
consumer interface.

Ideally nvmem provider driver should populate "cells" in struct 
nvmem_config after decoding them and then register nvmem provider.

That should just work!


--srini


> +	onie = kmalloc(sizeof(*onie), GFP_KERNEL);
> +	if (!onie) {
> +		err = -ENOMEM;
> +		goto err_nvmem_alloc;
> +	}
> +
> +	INIT_LIST_HEAD(&onie->attrs);
> +	onie->attr_count = 0;
> +	onie->nvmem = nvmem;
> +
> +	err = onie_nvmem_decode(onie);
> +	if (err)
> +		goto err_nvmem_decode;
> +
> +	if (!onie->attr_count) {
> +		pr_err("%s: has no ONIE attributes\n", nvmem_dev_name(nvmem));
> +		err = -EINVAL;
> +		goto err_no_attrs;
> +	}
> +
> +	cells = kmalloc_array(onie->attr_count, sizeof(*cells), GFP_KERNEL);
> +	if (!cells) {
> +		err = -ENOMEM;
> +		goto err_cells_alloc;
> +	}
> +
> +	onie->cell_lookup = kmalloc_array(onie->attr_count,
> +					  sizeof(struct nvmem_cell_lookup),
> +					  GFP_KERNEL);
> +	if (!onie->cell_lookup) {
> +		err = -ENOMEM;
> +		goto err_lookup_alloc;
> +	}
> +
> +	list_for_each_entry(attr, &onie->attrs, head) {
> +		struct nvmem_cell_lookup *lookup;
> +		struct nvmem_cell_info *cell;
> +
> +		cell = &cells[ncells];
> +
> +		lookup = &onie->cell_lookup[ncells];
> +		lookup->con_id = NULL;
> +
> +		cell->offset = attr->offset;
> +		cell->name = attr->name;
> +		cell->bytes = attr->len;
> +		cell->bit_offset = 0;
> +		cell->nbits = 0;
> +
> +		lookup->nvmem_name = nvmem_dev_name(onie->nvmem);
> +		lookup->dev_id = dev_name(dev);
> +		lookup->cell_name = cell->name;
> +		lookup->con_id = cell->name;
> +
> +		ncells++;
> +	}
> +
> +	onie->cell_tbl.nvmem_name = nvmem_dev_name(onie->nvmem);
> +	onie->cell_tbl.ncells = ncells;
> +	onie->cell_tbl.cells = cells;
> +
> +	nvmem_add_cell_table(&onie->cell_tbl);
> +	nvmem_add_cell_lookups(onie->cell_lookup, ncells);
> +
> +	dev_set_drvdata(dev, onie);
> +
> +	onie_nvmem_attrs_free(onie);
> +
> +	nvmem_device_put(nvmem);
> +
> +	return 0;
> +
> +err_lookup_alloc:
> +	kfree(onie->cell_tbl.cells);
> +err_cells_alloc:
> +	onie_nvmem_attrs_free(onie);
> +err_no_attrs:
> +err_nvmem_decode:
> +	kfree(onie);
> +err_nvmem_alloc:
> +	nvmem_device_put(nvmem);
> +
> +	return err;
> +}
> +

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-01  8:50   ` Srinivas Kandagatla
@ 2020-06-01  9:03     ` Vadym Kochan
  2020-06-01  9:13       ` Srinivas Kandagatla
  0 siblings, 1 reply; 10+ messages in thread
From: Vadym Kochan @ 2020-06-01  9:03 UTC (permalink / raw)
  To: Srinivas Kandagatla; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi

Hi,

On Mon, Jun 01, 2020 at 09:50:52AM +0100, Srinivas Kandagatla wrote:
> 
> 
> On 30/05/2020 00:04, Vadym Kochan wrote:
> > ONIE is a small operating system, pre-installed on bare metal network
> > switches, that provides an environment for automated provisioning.
> > 
> > This system requires that NVMEM (EEPROM) device holds various system
> > information (mac address, platform name, etc) in a special TLV layout.
> > 
> > The driver registers ONIE TLV attributes as NVMEM cells which can be
> > accessed by other platform driver. Also it allows to use
> > of_get_mac_address() to retrieve mac address for the netdev.
> > 
> > Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
> > ---
> >   drivers/nvmem/Kconfig      |   9 +
> >   drivers/nvmem/Makefile     |   3 +
> >   drivers/nvmem/onie-cells.c | 332 +++++++++++++++++++++++++++++++++++++
> 
> Is there a reason why Device tree bindings are missing for this driver?
> 
Sorry, I will do this, but I am not sure if even this driver is
conceptually acceptable.

> 
> 
> >   3 files changed, 344 insertions(+)
> >   create mode 100644 drivers/nvmem/onie-cells.c
> > 
> > diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> > index d7b7f6d688e7..dd9298487992 100644
> > --- a/drivers/nvmem/Kconfig
> > +++ b/drivers/nvmem/Kconfig
> > @@ -273,4 +273,13 @@ config SPRD_EFUSE
> >   	  This driver can also be built as a module. If so, the module
> >   	  will be called nvmem-sprd-efuse.
> > +config NVMEM_ONIE_CELLS
> > +	tristate "ONIE TLV cells support"
> > +	help
> > +	  This is a driver to provide cells from ONIE TLV structure stored
> > +	  on NVME device.
> > +
> > +	  This driver can also be built as a module. If so, the module
> > +	  will be called nvmem-onie-cells.
> > +
> >   endif
> > diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> > index a7c377218341..2199784a489f 100644
> > --- a/drivers/nvmem/Makefile
> > +++ b/drivers/nvmem/Makefile
> > @@ -55,3 +55,6 @@ obj-$(CONFIG_NVMEM_ZYNQMP)	+= nvmem_zynqmp_nvmem.o
> >   nvmem_zynqmp_nvmem-y		:= zynqmp_nvmem.o
> >   obj-$(CONFIG_SPRD_EFUSE)	+= nvmem_sprd_efuse.o
> >   nvmem_sprd_efuse-y		:= sprd-efuse.o
> > +
> > +obj-$(CONFIG_NVMEM_ONIE_CELLS)	+= nvmem-onie-cells.o
> > +nvmem-onie-cells-y		:= onie-cells.o
> > diff --git a/drivers/nvmem/onie-cells.c b/drivers/nvmem/onie-cells.c
> > new file mode 100644
> > index 000000000000..1e8b4b8d1c0d
> > --- /dev/null
> > +++ b/drivers/nvmem/onie-cells.c
> > @@ -0,0 +1,332 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * ONIE NVMEM cells provider
> > + *
> > + * Author: Vadym Kochan <vadym.kochan@plvision.eu>
> > + */
> > +
> > +#define ONIE_NVMEM_DRVNAME	"onie-nvmem-cells"
> > +
> > +#define pr_fmt(fmt) ONIE_NVMEM_DRVNAME ": " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/init.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/nvmem-consumer.h>
> > +#include <linux/nvmem-provider.h>
> > +
> > +#define ONIE_NVMEM_TLV_MAX_LEN	2048
> > +
> > +#define ONIE_NVMEM_HDR_ID	"TlvInfo"
> > +
> 
> ...
> 
> > +
> > +static int onie_nvmem_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *np = dev->of_node;
> > +	struct nvmem_cell_info *cells;
> > +	struct onie_nvmem_attr *attr;
> > +	struct nvmem_device *nvmem;
> > +	struct onie_nvmem *onie;
> > +	unsigned int ncells = 0;
> > +	int err;
> > +
> > +	nvmem = of_nvmem_device_get(np, NULL);
> > +	if (IS_ERR(nvmem))
> > +		return PTR_ERR(nvmem);
> > +
> TBH, this looks completely incorrect way to do this and misuse of nvmem
> consumer interface.
> 
> Ideally nvmem provider driver should populate "cells" in struct nvmem_config
> after decoding them and then register nvmem provider.
> 
> That should just work!
> 
> 
> --srini
But this is not nvmem provider but just describes the cells for any
nvmem device, because ONIE uses special TLV structure on the nvmem
device. So from the nvmem device point it is a consumer but provides the cells
for the given device.

> 
> 
> > +	onie = kmalloc(sizeof(*onie), GFP_KERNEL);
> > +	if (!onie) {
> > +		err = -ENOMEM;
> > +		goto err_nvmem_alloc;
> > +	}
> > +
> > +	INIT_LIST_HEAD(&onie->attrs);
> > +	onie->attr_count = 0;
> > +	onie->nvmem = nvmem;
> > +
> > +	err = onie_nvmem_decode(onie);
> > +	if (err)
> > +		goto err_nvmem_decode;
> > +
> > +	if (!onie->attr_count) {
> > +		pr_err("%s: has no ONIE attributes\n", nvmem_dev_name(nvmem));
> > +		err = -EINVAL;
> > +		goto err_no_attrs;
> > +	}
> > +
> > +	cells = kmalloc_array(onie->attr_count, sizeof(*cells), GFP_KERNEL);
> > +	if (!cells) {
> > +		err = -ENOMEM;
> > +		goto err_cells_alloc;
> > +	}
> > +
> > +	onie->cell_lookup = kmalloc_array(onie->attr_count,
> > +					  sizeof(struct nvmem_cell_lookup),
> > +					  GFP_KERNEL);
> > +	if (!onie->cell_lookup) {
> > +		err = -ENOMEM;
> > +		goto err_lookup_alloc;
> > +	}
> > +
> > +	list_for_each_entry(attr, &onie->attrs, head) {
> > +		struct nvmem_cell_lookup *lookup;
> > +		struct nvmem_cell_info *cell;
> > +
> > +		cell = &cells[ncells];
> > +
> > +		lookup = &onie->cell_lookup[ncells];
> > +		lookup->con_id = NULL;
> > +
> > +		cell->offset = attr->offset;
> > +		cell->name = attr->name;
> > +		cell->bytes = attr->len;
> > +		cell->bit_offset = 0;
> > +		cell->nbits = 0;
> > +
> > +		lookup->nvmem_name = nvmem_dev_name(onie->nvmem);
> > +		lookup->dev_id = dev_name(dev);
> > +		lookup->cell_name = cell->name;
> > +		lookup->con_id = cell->name;
> > +
> > +		ncells++;
> > +	}
> > +
> > +	onie->cell_tbl.nvmem_name = nvmem_dev_name(onie->nvmem);
> > +	onie->cell_tbl.ncells = ncells;
> > +	onie->cell_tbl.cells = cells;
> > +
> > +	nvmem_add_cell_table(&onie->cell_tbl);
> > +	nvmem_add_cell_lookups(onie->cell_lookup, ncells);
> > +
> > +	dev_set_drvdata(dev, onie);
> > +
> > +	onie_nvmem_attrs_free(onie);
> > +
> > +	nvmem_device_put(nvmem);
> > +
> > +	return 0;
> > +
> > +err_lookup_alloc:
> > +	kfree(onie->cell_tbl.cells);
> > +err_cells_alloc:
> > +	onie_nvmem_attrs_free(onie);
> > +err_no_attrs:
> > +err_nvmem_decode:
> > +	kfree(onie);
> > +err_nvmem_alloc:
> > +	nvmem_device_put(nvmem);
> > +
> > +	return err;
> > +}
> > +

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-01  9:03     ` Vadym Kochan
@ 2020-06-01  9:13       ` Srinivas Kandagatla
  2020-06-01 10:27         ` Vadym Kochan
  0 siblings, 1 reply; 10+ messages in thread
From: Srinivas Kandagatla @ 2020-06-01  9:13 UTC (permalink / raw)
  To: Vadym Kochan; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi



On 01/06/2020 10:03, Vadym Kochan wrote:
>>> +
>>> +	nvmem = of_nvmem_device_get(np, NULL);
>>> +	if (IS_ERR(nvmem))
>>> +		return PTR_ERR(nvmem);
>>> +
>> TBH, this looks completely incorrect way to do this and misuse of nvmem
>> consumer interface.
>>
>> Ideally nvmem provider driver should populate "cells" in struct nvmem_config
>> after decoding them and then register nvmem provider.
>>
>> That should just work!
>>
>>
>> --srini
> But this is not nvmem provider but just describes the cells for any
> nvmem device, because ONIE uses special TLV structure on the nvmem
> device. So from the nvmem device point it is a consumer but provides the cells
> for the given device.

That still falls under nvmem providers responsibility to parse these 
cells before registering it.

BTW, where is the provider driver for this in kernel?


--srini

> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-01  9:13       ` Srinivas Kandagatla
@ 2020-06-01 10:27         ` Vadym Kochan
  2020-06-05 10:53           ` Vadym Kochan
  0 siblings, 1 reply; 10+ messages in thread
From: Vadym Kochan @ 2020-06-01 10:27 UTC (permalink / raw)
  To: Srinivas Kandagatla; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi

On Mon, Jun 01, 2020 at 10:13:05AM +0100, Srinivas Kandagatla wrote:
> 
> 
> On 01/06/2020 10:03, Vadym Kochan wrote:
> > > > +
> > > > +	nvmem = of_nvmem_device_get(np, NULL);
> > > > +	if (IS_ERR(nvmem))
> > > > +		return PTR_ERR(nvmem);
> > > > +
> > > TBH, this looks completely incorrect way to do this and misuse of nvmem
> > > consumer interface.
> > > 
> > > Ideally nvmem provider driver should populate "cells" in struct nvmem_config
> > > after decoding them and then register nvmem provider.
> > > 
> > > That should just work!
> > > 
> > > 
> > > --srini
> > But this is not nvmem provider but just describes the cells for any
> > nvmem device, because ONIE uses special TLV structure on the nvmem
> > device. So from the nvmem device point it is a consumer but provides the cells
> > for the given device.
> 
> That still falls under nvmem providers responsibility to parse these cells
> before registering it.
OK, I thought that it is legal to have separate nvmem driver which
provides access to the device itself, and other driver which describes the
layout of the cells which might be applicable to any nvmem.

> 
> BTW, where is the provider driver for this in kernel ?
> 
> 
> --srini
> 
> > 
One of the example is atmel eeprom (at24), but there might be different
devices.

But can you please explain what is the technical/conceptual issue with
this approach ?

Thanks,

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-01 10:27         ` Vadym Kochan
@ 2020-06-05 10:53           ` Vadym Kochan
  2020-06-15 11:06             ` Srinivas Kandagatla
  0 siblings, 1 reply; 10+ messages in thread
From: Vadym Kochan @ 2020-06-05 10:53 UTC (permalink / raw)
  To: Srinivas Kandagatla; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi

Hi Srinivas,

On Mon, Jun 01, 2020 at 01:27:49PM +0300, Vadym Kochan wrote:
> On Mon, Jun 01, 2020 at 10:13:05AM +0100, Srinivas Kandagatla wrote:
> > 
> > 
> > On 01/06/2020 10:03, Vadym Kochan wrote:
> > > > > +
> > > > > +	nvmem = of_nvmem_device_get(np, NULL);
> > > > > +	if (IS_ERR(nvmem))
> > > > > +		return PTR_ERR(nvmem);
> > > > > +
> > > > TBH, this looks completely incorrect way to do this and misuse of nvmem
> > > > consumer interface.
> > > > 
> > > > Ideally nvmem provider driver should populate "cells" in struct nvmem_config
> > > > after decoding them and then register nvmem provider.
> > > > 
> > > > That should just work!
> > > > 
> > > > 
> > > > --srini
> > > But this is not nvmem provider but just describes the cells for any
> > > nvmem device, because ONIE uses special TLV structure on the nvmem
> > > device. So from the nvmem device point it is a consumer but provides the cells
> > > for the given device.
> > 
> > That still falls under nvmem providers responsibility to parse these cells
> > before registering it.
> OK, I thought that it is legal to have separate nvmem driver which
> provides access to the device itself, and other driver which describes the
> layout of the cells which might be applicable to any nvmem.
> 
> > 
> > BTW, where is the provider driver for this in kernel ?
> > 
> > 
> > --srini
> > 
> > > 
> One of the example is atmel eeprom (at24), but there might be different
> devices.
> 
> But can you please explain what is the technical/conceptual issue with
> this approach ?
> 
> Thanks,

I just I'd like to clarify if there is a way it can be acceptable. The
problem is that there is TLV format which  might be used on any nvmem
device which contains for example mac address which needs to be exposed
as nvmem cell. If to populate cells via nvmem_config then anyway I need
to parse these cells from the "target" nvmem device.

Thanks,

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-05 10:53           ` Vadym Kochan
@ 2020-06-15 11:06             ` Srinivas Kandagatla
  2020-08-14 11:56               ` Vadym Kochan
  0 siblings, 1 reply; 10+ messages in thread
From: Srinivas Kandagatla @ 2020-06-15 11:06 UTC (permalink / raw)
  To: Vadym Kochan; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi



On 05/06/2020 11:53, Vadym Kochan wrote:
>> One of the example is atmel eeprom (at24), but there might be different
>> devices.
>>
>> But can you please explain what is the technical/conceptual issue with
>> this approach ?
>>
>> Thanks,
> I just I'd like to clarify if there is a way it can be acceptable. The
> problem is that there is TLV format which  might be used on any nvmem
> device which contains for example mac address which needs to be exposed
> as nvmem cell. If to populate cells via nvmem_config then anyway I need
> to parse these cells from the "target" nvmem device.



As a first step this need to be part of the provider logic to parse this 
before nvmem provider is registered. If there are more users for such 
parsing, we can think of adding some level of parsing to nvmem core itself.

Hope this answers your query.

Thanks,
srini

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support
  2020-06-15 11:06             ` Srinivas Kandagatla
@ 2020-08-14 11:56               ` Vadym Kochan
  0 siblings, 0 replies; 10+ messages in thread
From: Vadym Kochan @ 2020-08-14 11:56 UTC (permalink / raw)
  To: Srinivas Kandagatla; +Cc: linux-kernel, Greg Kroah-Hartman, Taras Chornyi

Hi Srinivas,

On Mon, Jun 15, 2020 at 12:06:11PM +0100, Srinivas Kandagatla wrote:
> 
> 
> On 05/06/2020 11:53, Vadym Kochan wrote:
> > > One of the example is atmel eeprom (at24), but there might be different
> > > devices.
> > > 
> > > But can you please explain what is the technical/conceptual issue with
> > > this approach ?
> > > 
> > > Thanks,
> > I just I'd like to clarify if there is a way it can be acceptable. The
> > problem is that there is TLV format which  might be used on any nvmem
> > device which contains for example mac address which needs to be exposed
> > as nvmem cell. If to populate cells via nvmem_config then anyway I need
> > to parse these cells from the "target" nvmem device.
> 
> 
> 
> As a first step this need to be part of the provider logic to parse this
> before nvmem provider is registered. If there are more users for such
> parsing, we can think of adding some level of parsing to nvmem core itself.
> 
> Hope this answers your query.
> 
> Thanks,
> srini

Thank you for suggestion, I did not answered because I was not sure
about the way how to provide this cell parser registering, still
I am not sure about the preferred way. What about the following way:

    1) nvmem provides API for registering cell-parser.

       Looks like it might be similar to the API for adding the
       cell-table by using device's name.

    2) cell-parser driver registers itself using API from above
       (I am not sure on which initcall stage better to perform
       registration to be registered before the nvmem drivers probe)

    3) during nvmem_register() (before adding cells from table) core
       tries to find parser by matching on device's name.
       
       If parser is found - then core calls the callback with passing the pointer to
       nvmem device.

    4) cell-driver is called via on-parse callback.

       During this callback the cell-parser driver can parse the nvmem
       device and register cell table.

    5) core adds cells from registered tables.


Thank you,

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-08-14 11:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-29 23:04 [PATCH v2 0/2] nvmem: add ONIE NVMEM cells provider Vadym Kochan
2020-05-29 23:04 ` [PATCH v2 1/2] nvmem: core: allow to register cells for existing device Vadym Kochan
2020-05-29 23:04 ` [PATCH v2 2/2] nvmem: add ONIE NVMEM cells support Vadym Kochan
2020-06-01  8:50   ` Srinivas Kandagatla
2020-06-01  9:03     ` Vadym Kochan
2020-06-01  9:13       ` Srinivas Kandagatla
2020-06-01 10:27         ` Vadym Kochan
2020-06-05 10:53           ` Vadym Kochan
2020-06-15 11:06             ` Srinivas Kandagatla
2020-08-14 11:56               ` Vadym Kochan

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).