diff mbox series

[v7,7/7] mtd: ubi: provide NVMEM layer over UBI volumes

Message ID 82ceb13954f7e701bf47c112333e7b15a57fc360.1702952891.git.daniel@makrotopia.org
State Accepted
Headers show
Series mtd: ubi: allow UBI volumes to provide NVMEM | expand

Commit Message

Daniel Golle Dec. 19, 2023, 2:33 a.m. UTC
In an ideal world we would like UBI to be used where ever possible on a
NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
is possible to achieve an (almost-)all-UBI flash layout. Hence the need
for a way to also use UBI volumes to store board-level constants, such
as MAC addresses and calibration data of wireless interfaces.

Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
providers. Allow UBI devices to have a "volumes" firmware subnode with
volumes which may be compatible with "nvmem-cells".
Access to UBI volumes via the NVMEM interface at this point is
read-only, and it is slow, opening and closing the UBI volume for each
access due to limitations of the NVMEM provider API.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
 drivers/mtd/ubi/Kconfig  |  12 +++
 drivers/mtd/ubi/Makefile |   1 +
 drivers/mtd/ubi/nvmem.c  | 188 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 201 insertions(+)
 create mode 100644 drivers/mtd/ubi/nvmem.c

Comments

Miquel Raynal Feb. 19, 2024, 11:01 a.m. UTC | #1
Hi Daniel,

daniel@makrotopia.org wrote on Tue, 19 Dec 2023 02:33:48 +0000:

> In an ideal world we would like UBI to be used where ever possible on a
> NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
> is possible to achieve an (almost-)all-UBI flash layout. Hence the need
> for a way to also use UBI volumes to store board-level constants, such
> as MAC addresses and calibration data of wireless interfaces.
> 
> Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
> providers. Allow UBI devices to have a "volumes" firmware subnode with
> volumes which may be compatible with "nvmem-cells".
> Access to UBI volumes via the NVMEM interface at this point is
> read-only, and it is slow, opening and closing the UBI volume for each
> access due to limitations of the NVMEM provider API.

I don't feel qualified enough to review the other patches, however this
one looks good to me.

Thanks,
Miquèl
Richard Weinberger Feb. 25, 2024, 10:12 p.m. UTC | #2
----- Ursprüngliche Mail -----
> Von: "Miquel Raynal" <miquel.raynal@bootlin.com>
> An: "Daniel Golle" <daniel@makrotopia.org>
> CC: "richard" <richard@nod.at>, "Vignesh Raghavendra" <vigneshr@ti.com>, "Rob Herring" <robh+dt@kernel.org>, "Krzysztof
> Kozlowski" <krzysztof.kozlowski+dt@linaro.org>, "Conor Dooley" <conor+dt@kernel.org>, "linux-mtd"
> <linux-mtd@lists.infradead.org>, "devicetree" <devicetree@vger.kernel.org>, "linux-kernel"
> <linux-kernel@vger.kernel.org>
> Gesendet: Montag, 19. Februar 2024 12:01:56
> Betreff: Re: [PATCH v7 7/7] mtd: ubi: provide NVMEM layer over UBI volumes

> Hi Daniel,
> 
> daniel@makrotopia.org wrote on Tue, 19 Dec 2023 02:33:48 +0000:
> 
>> In an ideal world we would like UBI to be used where ever possible on a
>> NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
>> is possible to achieve an (almost-)all-UBI flash layout. Hence the need
>> for a way to also use UBI volumes to store board-level constants, such
>> as MAC addresses and calibration data of wireless interfaces.
>> 
>> Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
>> providers. Allow UBI devices to have a "volumes" firmware subnode with
>> volumes which may be compatible with "nvmem-cells".
>> Access to UBI volumes via the NVMEM interface at this point is
>> read-only, and it is slow, opening and closing the UBI volume for each
>> access due to limitations of the NVMEM provider API.
> 
> I don't feel qualified enough to review the other patches, however this
> one looks good to me.

Finally(!), I had enough time to look.
Thanks for addressing all my comments form the previous series.
Patches applied.

I have only one tiny request, can you share the lockdep spalt
you encountered in ubi_notify_add() regarding mtd_table_mutex
and ubi_devices_mutex? The solutions looks okay to me, but
if you have more details that would be great.

Thanks,
//richard
Daniel Golle Feb. 26, 2024, 12:05 a.m. UTC | #3
Hi Richard,

On Sun, Feb 25, 2024 at 11:12:54PM +0100, Richard Weinberger wrote:
> ----- Ursprüngliche Mail -----
> > Von: "Miquel Raynal" <miquel.raynal@bootlin.com>
> > An: "Daniel Golle" <daniel@makrotopia.org>
> > CC: "richard" <richard@nod.at>, "Vignesh Raghavendra" <vigneshr@ti.com>, "Rob Herring" <robh+dt@kernel.org>, "Krzysztof
> > Kozlowski" <krzysztof.kozlowski+dt@linaro.org>, "Conor Dooley" <conor+dt@kernel.org>, "linux-mtd"
> > <linux-mtd@lists.infradead.org>, "devicetree" <devicetree@vger.kernel.org>, "linux-kernel"
> > <linux-kernel@vger.kernel.org>
> > Gesendet: Montag, 19. Februar 2024 12:01:56
> > Betreff: Re: [PATCH v7 7/7] mtd: ubi: provide NVMEM layer over UBI volumes
> 
> > Hi Daniel,
> > 
> > daniel@makrotopia.org wrote on Tue, 19 Dec 2023 02:33:48 +0000:
> > 
> >> In an ideal world we would like UBI to be used where ever possible on a
> >> NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
> >> is possible to achieve an (almost-)all-UBI flash layout. Hence the need
> >> for a way to also use UBI volumes to store board-level constants, such
> >> as MAC addresses and calibration data of wireless interfaces.
> >> 
> >> Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
> >> providers. Allow UBI devices to have a "volumes" firmware subnode with
> >> volumes which may be compatible with "nvmem-cells".
> >> Access to UBI volumes via the NVMEM interface at this point is
> >> read-only, and it is slow, opening and closing the UBI volume for each
> >> access due to limitations of the NVMEM provider API.
> > 
> > I don't feel qualified enough to review the other patches, however this
> > one looks good to me.
> 
> Finally(!), I had enough time to look.
> Thanks for addressing all my comments form the previous series.
> Patches applied.

It's an enourmous coicident that you are writing just now that I found
a sizeof(int)-related problem which triggers a compiler warning when
building the UBI NVMEM provider on 32-bit platforms. I was just about
to prepare an updated series. Literally in this minute.
Should I still send the whole updates series or only the final patch
(as the necessary change is there) or a follow-up patch fixing the
original patch?

> 
> I have only one tiny request, can you share the lockdep spalt
> you encountered in ubi_notify_add() regarding mtd_table_mutex
> and ubi_devices_mutex? The solutions looks okay to me, but
> if you have more details that would be great.

I will setup a test build to reproduce the original warning and
let you know shortly.


Cheers


Daniel
Richard Weinberger March 10, 2024, 9:17 p.m. UTC | #4
Daniel,

----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
>> Finally(!), I had enough time to look.
>> Thanks for addressing all my comments form the previous series.
>> Patches applied.
> 
> It's an enourmous coicident that you are writing just now that I found
> a sizeof(int)-related problem which triggers a compiler warning when
> building the UBI NVMEM provider on 32-bit platforms. I was just about
> to prepare an updated series. Literally in this minute.
> Should I still send the whole updates series or only the final patch
> (as the necessary change is there) or a follow-up patch fixing the
> original patch?

I have just merged your fixup patch. So all good.

>> 
>> I have only one tiny request, can you share the lockdep spalt
>> you encountered in ubi_notify_add() regarding mtd_table_mutex
>> and ubi_devices_mutex? The solutions looks okay to me, but
>> if you have more details that would be great.
> 
> I will setup a test build to reproduce the original warning and
> let you know shortly.

Any news on that?

BTW: Is there a nice way to test this with nandsim in qemu?
I'd love being able to test all ubi attach code paths on my test setup.

Thanks,
//richard
Daniel Golle March 11, 2024, 2:37 a.m. UTC | #5
Hi Richard,

On Sun, Mar 10, 2024 at 10:17:17PM +0100, Richard Weinberger wrote:
> Daniel,
> 
> ----- Ursprüngliche Mail -----
> > Von: "Daniel Golle" <daniel@makrotopia.org>
> >> Finally(!), I had enough time to look.
> >> Thanks for addressing all my comments form the previous series.
> >> Patches applied.
> > 
> > It's an enourmous coicident that you are writing just now that I found
> > a sizeof(int)-related problem which triggers a compiler warning when
> > building the UBI NVMEM provider on 32-bit platforms. I was just about
> > to prepare an updated series. Literally in this minute.
> > Should I still send the whole updates series or only the final patch
> > (as the necessary change is there) or a follow-up patch fixing the
> > original patch?
> 
> I have just merged your fixup patch. So all good.

Thank you!

> 
> >> 
> >> I have only one tiny request, can you share the lockdep spalt
> >> you encountered in ubi_notify_add() regarding mtd_table_mutex
> >> and ubi_devices_mutex? The solutions looks okay to me, but
> >> if you have more details that would be great.
> > 
> > I will setup a test build to reproduce the original warning and
> > let you know shortly.
> 
> Any news on that?

I've tried for days now to reproduce this on recent kernels and fail
to do so. Ie. when using regular mutex_lock() instead of
mutex_lock_nested() I no longer see any lockdep warning with
linux-next. It could be that I'm chasing a lockdep ghost...

> BTW: Is there a nice way to test this with nandsim in qemu?
> I'd love being able to test all ubi attach code paths on my test setup.

From what I can tell 'nandsim' doesn't have a way to be defined in
Device Tree, making it unsuitable to test the attachment of UBI in
this way.

However, QEMU does support emulating TI OMAP's OneNAND controller, eg.
as part of the Nokia N810 hardware supported by qemu-system-arm, see

https://www.qemu.org/docs/master/system/arm/nseries.html

So we could use that and modify the device tree in Linux to have a MTD
partition for UBI and 'compatible = "linux,ubi";' set therein:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/ti/omap/omap2420-n8x0-common.dtsi#n84

If you like I can prepare such a test setup.

Is there a repository for MTD/UBI tests to be run on QEMU which I should
contribute this to?


Cheers


Daniel
Richard Weinberger March 19, 2024, 10:31 p.m. UTC | #6
----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
>> BTW: Is there a nice way to test this with nandsim in qemu?
>> I'd love being able to test all ubi attach code paths on my test setup.
> 
> From what I can tell 'nandsim' doesn't have a way to be defined in
> Device Tree, making it unsuitable to test the attachment of UBI in
> this way.
> 
> However, QEMU does support emulating TI OMAP's OneNAND controller, eg.
> as part of the Nokia N810 hardware supported by qemu-system-arm, see
> 
> https://www.qemu.org/docs/master/system/arm/nseries.html
> 
> So we could use that and modify the device tree in Linux to have a MTD
> partition for UBI and 'compatible = "linux,ubi";' set therein:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/ti/omap/omap2420-n8x0-common.dtsi#n84
> 
> If you like I can prepare such a test setup.

This would be great!

> Is there a repository for MTD/UBI tests to be run on QEMU which I should
> contribute this to?

UBI tests reside in the mtd-utils repository.
http://git.infradead.org/?p=mtd-utils.git;a=tree;f=tests/ubi-tests;h=20fd6a043eeb96a81736dd07885f74e4e0bb0cc0;hb=HEAD

Maybe you can provide a small shell script which configures qemu?
It doesn't have to be fancy, just something David or I can use as staring point.

Thanks,
//richard
Daniel Golle March 22, 2024, 3:56 p.m. UTC | #7
On Tue, Mar 19, 2024 at 11:31:18PM +0100, Richard Weinberger wrote:
> ----- Ursprüngliche Mail -----
> > Von: "Daniel Golle" <daniel@makrotopia.org>
> >> BTW: Is there a nice way to test this with nandsim in qemu?
> >> I'd love being able to test all ubi attach code paths on my test setup.
> > 
> > From what I can tell 'nandsim' doesn't have a way to be defined in
> > Device Tree, making it unsuitable to test the attachment of UBI in
> > this way.
> > 
> > However, QEMU does support emulating TI OMAP's OneNAND controller, eg.
> > as part of the Nokia N810 hardware supported by qemu-system-arm, see
> > 
> > https://www.qemu.org/docs/master/system/arm/nseries.html
> > 
> > So we could use that and modify the device tree in Linux to have a MTD
> > partition for UBI and 'compatible = "linux,ubi";' set therein:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/ti/omap/omap2420-n8x0-common.dtsi#n84
> > 
> > If you like I can prepare such a test setup.
> 
> This would be great!
> 
> > Is there a repository for MTD/UBI tests to be run on QEMU which I should
> > contribute this to?
> 
> UBI tests reside in the mtd-utils repository.
> http://git.infradead.org/?p=mtd-utils.git;a=tree;f=tests/ubi-tests;h=20fd6a043eeb96a81736dd07885f74e4e0bb0cc0;hb=HEAD
> 
> Maybe you can provide a small shell script which configures qemu?
> It doesn't have to be fancy, just something David or I can use as staring point.

I'm working on it but it turns out to be a bit more difficult than I
thought it would be, because

 * the only devices with NAND flash emulated in QEMU or Nokia N800 and
   N810 as well as some even more ancient Intel PXA270 based PDA like
   the Sharp 'spitz'.

 * QEMU support for the N800 and N810 has apparently been bitrotting and
   is broken at least since 2019, nobody seems to care much.

 * The spitz predates device tree and hence is unsuitable for testing
   attachment of UBI via DT. But it at least boots because Guenter Roeck
   makes sure it does[1].

I was about to create a spitz-like imaginary board with DT, but also that
doesn't seem to be completely trivial.

So: hold my beer, I'll be back shortly ;)

If anyone has better ideas on how to utilize support for raw NAND or the
OneNAND controller in QEMU in a device-tree environment which actually
works, that'd be great. Obviously I don't care about other peripherals
like Bluetooth and all the complicated stuff of the N80x...

[1]: https://github.com/groeck/linux-build-test/blob/master/rootfs/arm/run-qemu-arm.sh#L64
Richard Weinberger March 22, 2024, 4:05 p.m. UTC | #8
----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
> So: hold my beer, I'll be back shortly ;)
> 
> If anyone has better ideas on how to utilize support for raw NAND or the
> OneNAND controller in QEMU in a device-tree environment which actually
> works, that'd be great. Obviously I don't care about other peripherals
> like Bluetooth and all the complicated stuff of the N80x...

Speaking of "hold my beer", maybe we can hack something into nandsim
to act like a device tree attachable device?
In theory, device tree is also available on x86 and other non-embedded archs.

Thanks,
//richard
diff mbox series

Patch

diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 2ed77b7b3fcb5..45d939bbfa853 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -104,4 +104,16 @@  config MTD_UBI_BLOCK
 
 	   If in doubt, say "N".
 
+config MTD_UBI_NVMEM
+	tristate "UBI virtual NVMEM"
+	default n
+	depends on NVMEM
+	help
+	   This option enabled an additional driver exposing UBI volumes as NVMEM
+	   providers, intended for platforms where UBI is part of the firmware
+	   specification and used to store also e.g. MAC addresses or board-
+	   specific Wi-Fi calibration data.
+
+	   If in doubt, say "N".
+
 endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index 543673605ca72..4b51aaf00d1a2 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -7,3 +7,4 @@  ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
 ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
 
 obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
diff --git a/drivers/mtd/ubi/nvmem.c b/drivers/mtd/ubi/nvmem.c
new file mode 100644
index 0000000000000..b7a93c495d172
--- /dev/null
+++ b/drivers/mtd/ubi/nvmem.c
@@ -0,0 +1,188 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
+ */
+
+/* UBI NVMEM provider */
+#include "ubi.h"
+#include <linux/nvmem-provider.h>
+#include <asm/div64.h>
+
+/* List of all NVMEM devices */
+static LIST_HEAD(nvmem_devices);
+static DEFINE_MUTEX(devices_mutex);
+
+struct ubi_nvmem {
+	struct nvmem_device *nvmem;
+	int ubi_num;
+	int vol_id;
+	int usable_leb_size;
+	struct list_head list;
+};
+
+static int ubi_nvmem_reg_read(void *priv, unsigned int from,
+			      void *val, size_t bytes)
+{
+	int err = 0, lnum = from, offs, bytes_left = bytes, to_read;
+	struct ubi_nvmem *unv = priv;
+	struct ubi_volume_desc *desc;
+
+	desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	offs = do_div(lnum, unv->usable_leb_size);
+	while (bytes_left) {
+		to_read = unv->usable_leb_size - offs;
+
+		if (to_read > bytes_left)
+			to_read = bytes_left;
+
+		err = ubi_read(desc, lnum, val, offs, to_read);
+		if (err)
+			break;
+
+		lnum += 1;
+		offs = 0;
+		bytes_left -= to_read;
+		val += to_read;
+	}
+	ubi_close_volume(desc);
+
+	if (err)
+		return err;
+
+	return bytes_left == 0 ? 0 : -EIO;
+}
+
+static int ubi_nvmem_add(struct ubi_volume_info *vi)
+{
+	struct device_node *np = dev_of_node(vi->dev);
+	struct nvmem_config config = {};
+	struct ubi_nvmem *unv;
+	int ret;
+
+	if (!np)
+		return 0;
+
+	if (!of_get_child_by_name(np, "nvmem-layout"))
+		return 0;
+
+	if (WARN_ON_ONCE(vi->usable_leb_size <= 0) ||
+	    WARN_ON_ONCE(vi->size <= 0))
+		return -EINVAL;
+
+	unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
+	if (!unv)
+		return -ENOMEM;
+
+	config.id = NVMEM_DEVID_NONE;
+	config.dev = vi->dev;
+	config.name = dev_name(vi->dev);
+	config.owner = THIS_MODULE;
+	config.priv = unv;
+	config.reg_read = ubi_nvmem_reg_read;
+	config.size = vi->usable_leb_size * vi->size;
+	config.word_size = 1;
+	config.stride = 1;
+	config.read_only = true;
+	config.root_only = true;
+	config.ignore_wp = true;
+	config.of_node = np;
+
+	unv->ubi_num = vi->ubi_num;
+	unv->vol_id = vi->vol_id;
+	unv->usable_leb_size = vi->usable_leb_size;
+	unv->nvmem = nvmem_register(&config);
+	if (IS_ERR(unv->nvmem)) {
+		ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
+				    "Failed to register NVMEM device\n");
+		kfree(unv);
+		return ret;
+	}
+
+	mutex_lock(&devices_mutex);
+	list_add_tail(&unv->list, &nvmem_devices);
+	mutex_unlock(&devices_mutex);
+
+	return 0;
+}
+
+static void ubi_nvmem_remove(struct ubi_volume_info *vi)
+{
+	struct ubi_nvmem *unv_c, *unv = NULL;
+
+	mutex_lock(&devices_mutex);
+	list_for_each_entry(unv_c, &nvmem_devices, list)
+		if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
+			unv = unv_c;
+			break;
+		}
+
+	if (!unv) {
+		mutex_unlock(&devices_mutex);
+		return;
+	}
+
+	list_del(&unv->list);
+	mutex_unlock(&devices_mutex);
+	nvmem_unregister(unv->nvmem);
+	kfree(unv);
+}
+
+/**
+ * nvmem_notify - UBI notification handler.
+ * @nb: registered notifier block
+ * @l: notification type
+ * @ns_ptr: pointer to the &struct ubi_notification object
+ */
+static int nvmem_notify(struct notifier_block *nb, unsigned long l,
+			 void *ns_ptr)
+{
+	struct ubi_notification *nt = ns_ptr;
+
+	switch (l) {
+	case UBI_VOLUME_RESIZED:
+		ubi_nvmem_remove(&nt->vi);
+		fallthrough;
+	case UBI_VOLUME_ADDED:
+		ubi_nvmem_add(&nt->vi);
+		break;
+	case UBI_VOLUME_SHUTDOWN:
+		ubi_nvmem_remove(&nt->vi);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block nvmem_notifier = {
+	.notifier_call = nvmem_notify,
+};
+
+static int __init ubi_nvmem_init(void)
+{
+	return ubi_register_volume_notifier(&nvmem_notifier, 0);
+}
+
+static void __exit ubi_nvmem_exit(void)
+{
+	struct ubi_nvmem *unv, *tmp;
+
+	mutex_lock(&devices_mutex);
+	list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
+		nvmem_unregister(unv->nvmem);
+		list_del(&unv->list);
+		kfree(unv);
+	}
+	mutex_unlock(&devices_mutex);
+
+	ubi_unregister_volume_notifier(&nvmem_notifier);
+}
+
+module_init(ubi_nvmem_init);
+module_exit(ubi_nvmem_exit);
+MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
+MODULE_AUTHOR("Daniel Golle");
+MODULE_LICENSE("GPL");