From: Loic Poulain <loic.poulain@oss.qualcomm.com>
To: Ulf Hansson <ulfh@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>,
Jens Axboe <axboe@kernel.dk>,
Johannes Berg <johannes@sipsolutions.net>,
Jeff Johnson <jjohnson@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Marcel Holtmann <marcel@holtmann.org>,
Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
Balakrishna Godavarthi <quic_bgodavar@quicinc.com>,
Rocky Liao <quic_rjliao@quicinc.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Srinivas Kandagatla <srini@kernel.org>,
Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
Saravana Kannan <saravanak@kernel.org>,
Christian Marangi <ansuelsmth@gmail.com>
Cc: linux-mmc@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-block@vger.kernel.org, linux-wireless@vger.kernel.org,
ath10k@lists.infradead.org, linux-bluetooth@vger.kernel.org,
netdev@vger.kernel.org, daniel@makrotopia.org,
Loic Poulain <loic.poulain@oss.qualcomm.com>,
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Subject: [PATCH v10 06/10] block: implement NVMEM provider
Date: Thu, 06 Aug 2026 16:38:39 +0200 [thread overview]
Message-ID: <20260806-block-as-nvmem-v10-6-be598b2a5606@oss.qualcomm.com> (raw)
In-Reply-To: <20260806-block-as-nvmem-v10-0-be598b2a5606@oss.qualcomm.com>
On embedded devices using an eMMC it is common that one or more partitions
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
data. Allow referencing the partition in device tree for the kernel and
Wi-Fi drivers accessing it via the NVMEM layer.
NVMEM is registered for a block device whose OF node describes an NVMEM
layout, either via an "nvmem-layout" child or by being a "fixed-layout"
node itself (e.g. an eMMC boot partition associated through its mmc-card
node).
The NVMEM device is a read-only side channel onto a block device.
Each read opens the block device with BLK_OPEN_EXCL to keep other
exclusive openers away for the duration of the access.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
block/Kconfig | 11 +++++
block/Makefile | 1 +
block/blk-nvmem.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++
block/blk.h | 8 ++++
block/genhd.c | 4 ++
block/partitions/core.c | 5 +++
include/linux/blk_types.h | 4 ++
7 files changed, 145 insertions(+)
diff --git a/block/Kconfig b/block/Kconfig
index 70e4a66d941ff66ecb0ec34f4f7eff7fd1e4be40..4899ad572c71ffdbb62460d57623216254893ddc 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -209,6 +209,17 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
by falling back to the kernel crypto API when inline
encryption hardware is not present.
+config BLK_NVMEM
+ bool "Block device NVMEM provider"
+ depends on OF
+ depends on NVMEM
+ help
+ Allow block devices (or partitions) to act as NVMEM providers,
+ exposing factory-provisioned data such as MAC addresses or Wi-Fi
+ calibration blobs to the drivers that consume them. This is
+ typically used on embedded devices where such data is stored in a
+ dedicated area of an eMMC, instead of a separate EEPROM or OTP.
+
source "block/partitions/Kconfig"
config BLK_PM
diff --git a/block/Makefile b/block/Makefile
index e7bd320e3d6971a8abf584f5de42776bb54e8216..8200297fbcbab304beb4239d0c33da07011c3ed9 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
blk-crypto-sysfs.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
+obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..69b69184e16303444c9cb2dc816d5679daeb13c4
--- /dev/null
+++ b/block/blk-nvmem.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * block device NVMEM provider
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Useful on devices using a whole disk or a partition (e.g. an eMMC boot
+ * partition) to store MAC addresses, Bluetooth addresses or Wi-Fi
+ * calibration EEPROM data.
+ *
+ * The NVMEM device is a side channel onto a block device that stays fully
+ * usable. This is somewhat mitigated by opening the device exclusively.
+ */
+
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/property.h>
+
+#include "blk.h"
+
+static int blk_nvmem_reg_read(void *priv, unsigned int from,
+ void *val, size_t bytes)
+{
+ struct block_device *bdev = priv;
+ struct file *bdev_file;
+ loff_t pos = from;
+ ssize_t ret;
+
+ /* open and prevent other exclusive openers */
+ bdev_file = bdev_file_open_by_dev(bdev->bd_dev,
+ BLK_OPEN_READ | BLK_OPEN_EXCL,
+ blk_nvmem_reg_read, NULL);
+ if (IS_ERR(bdev_file))
+ return PTR_ERR(bdev_file);
+
+ if (file_bdev(bdev_file) != bdev) {
+ fput(bdev_file);
+ return -ENODEV;
+ }
+
+ ret = kernel_read(bdev_file, val, bytes, &pos);
+ fput(bdev_file);
+
+ if (ret < 0)
+ return ret;
+ if (ret != bytes)
+ return -EIO;
+ return 0;
+}
+
+int blk_nvmem_add(struct block_device *bdev)
+{
+ struct device *dev = &bdev->bd_device;
+ struct device_node *np = dev_of_node(dev);
+ struct nvmem_config config = {
+ .id = NVMEM_DEVID_NONE,
+ .owner = THIS_MODULE,
+ .word_size = 1,
+ .stride = 1,
+ .read_only = true,
+ .root_only = true,
+ .ignore_wp = true,
+ };
+ struct nvmem_device *nvmem;
+ struct device_node *child;
+
+ /* skip devices which do not have a device tree node */
+ if (!np)
+ return 0;
+
+ /*
+ * The layout is described either by an "nvmem-layout" child node or
+ * by the device node itself being a "fixed-layout" container.
+ */
+ child = of_get_child_by_name(np, "nvmem-layout");
+ if (child)
+ of_node_put(child);
+ else if (!of_device_is_compatible(np, "fixed-layout"))
+ return 0;
+
+ if (bdev_nr_bytes(bdev) > INT_MAX) {
+ dev_warn(dev, "block device too large to be an NVMEM\n");
+ return 0;
+ }
+
+ config.dev = dev;
+ config.name = dev_name(dev);
+ config.priv = bdev;
+ config.reg_read = blk_nvmem_reg_read;
+ config.size = bdev_nr_bytes(bdev);
+ config.of_node = np;
+
+ nvmem = nvmem_register(&config);
+ if (IS_ERR(nvmem))
+ return dev_err_probe(dev, PTR_ERR(nvmem),
+ "Failed to register NVMEM device\n");
+
+ bdev->bd_nvmem = nvmem;
+
+ return 0;
+}
+
+void blk_nvmem_del(struct block_device *bdev)
+{
+ nvmem_unregister(bdev->bd_nvmem);
+ bdev->bd_nvmem = NULL;
+}
diff --git a/block/blk.h b/block/blk.h
index 25af8ac5ef0f77c09b4d747827b275c32e9f2972..dad8f0d7a218edbafa9b6a03aed673657f3e8cbb 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -810,4 +810,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
memalloc_noio_restore(memflags);
}
+#ifdef CONFIG_BLK_NVMEM
+int blk_nvmem_add(struct block_device *bdev);
+void blk_nvmem_del(struct block_device *bdev);
+#else
+static inline int blk_nvmem_add(struct block_device *bdev) { return 0; }
+static inline void blk_nvmem_del(struct block_device *bdev) {}
+#endif
+
#endif /* BLK_INTERNAL_H */
diff --git a/block/genhd.c b/block/genhd.c
index f84b6a355b574af88c870938a8c69aeb9f8f44ad..0c9c5e5ea7baffa326a2d45b075688cf3a0edf5a 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
*/
dev_set_uevent_suppress(ddev, 0);
disk_uevent(disk, KOBJ_ADD);
+
+ blk_nvmem_add(disk->part0);
}
blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
@@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
disk_del_events(disk);
+ blk_nvmem_del(disk->part0);
+
/*
* Prevent new openers by unlinked the bdev inode.
*/
diff --git a/block/partitions/core.c b/block/partitions/core.c
index eee954df1ac6ef7dd4f02ad5c9d49aed778bf015..c83227710584a6feb25c8abae3b319cfae9cce5b 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -289,6 +289,8 @@ void drop_partition(struct block_device *part)
xa_erase(&part->bd_disk->part_tbl, bdev_partno(part));
kobject_put(part->bd_holder_dir);
+ blk_nvmem_del(part);
+
device_del(&part->bd_device);
put_device(&part->bd_device);
}
@@ -406,6 +408,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
/* suppress uevent if the disk suppresses it */
if (!dev_get_uevent_suppress(ddev))
kobject_uevent(&pdev->kobj, KOBJ_ADD);
+
+ blk_nvmem_add(bdev);
+
return bdev;
out_del:
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c09e0ceaac41ba59e86fb0c4efc64..6ed173c649025b95cce9253b27f68f2c7dbab8eb 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -15,6 +15,7 @@
struct bio_set;
struct bio;
struct bio_integrity_payload;
+struct nvmem_device;
struct page;
struct io_context;
struct cgroup_subsys_state;
@@ -73,6 +74,9 @@ struct block_device {
int bd_writers;
#ifdef CONFIG_SECURITY
void *bd_security;
+#endif
+#ifdef CONFIG_BLK_NVMEM
+ struct nvmem_device *bd_nvmem;
#endif
/*
* keep this out-of-line as it's both big and not needed in the fast
--
2.34.1
next prev parent reply other threads:[~2026-08-06 14:39 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 14:38 [PATCH v10 00/10] Support for block device NVMEM providers Loic Poulain
2026-08-06 14:38 ` [PATCH v10 01/10] dt-bindings: mmc: Document fixed-layout NVMEM provider support Loic Poulain
2026-09-04 8:49 ` Ulf Hansson
2026-08-06 14:38 ` [PATCH v10 02/10] dt-bindings: net: wireless: qcom,ath10k: Document NVMEM cells Loic Poulain
2026-08-06 14:38 ` [PATCH v10 03/10] dt-bindings: bluetooth: qcom: Add NVMEM BD address cell Loic Poulain
2026-08-06 14:38 ` [PATCH v10 04/10] nvmem: layouts: Support fixed-layout as the nvmem device node itself Loic Poulain
2026-09-21 9:27 ` Srinivas Kandagatla
2026-08-06 14:38 ` [PATCH v10 05/10] block: partitions: of: Attach partition fwnode to the block device Loic Poulain
2026-08-06 14:38 ` Loic Poulain [this message]
2026-08-06 14:38 ` [PATCH v10 07/10] net: of_net: Add of_get_nvmem_eui48() helper for EUI-48 lookup Loic Poulain
2026-08-06 14:38 ` [PATCH v10 08/10] Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval Loic Poulain
2026-08-06 14:38 ` [PATCH v10 09/10] Bluetooth: qca: Set NVMEM BD address quirks when address is invalid Loic Poulain
2026-08-06 14:38 ` [PATCH v10 10/10] arm64: dts: qcom: arduino-imola: Add NVMEM layout for WiFi/BT Loic Poulain
2026-09-21 9:26 ` (subset) [PATCH v10 00/10] Support for block device NVMEM providers Srinivas Kandagatla
2026-09-25 13:38 ` Loic Poulain
2026-09-25 14:10 ` Jeff Johnson
2026-09-25 18:42 ` Loic Poulain
2026-09-25 22:22 ` Jeff Johnson
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=20260806-block-as-nvmem-v10-6-be598b2a5606@oss.qualcomm.com \
--to=loic.poulain@oss.qualcomm.com \
--cc=andersson@kernel.org \
--cc=andrew@lunn.ch \
--cc=ansuelsmth@gmail.com \
--cc=ath10k@lists.infradead.org \
--cc=axboe@kernel.dk \
--cc=bartosz.golaszewski@oss.qualcomm.com \
--cc=brgl@kernel.org \
--cc=conor+dt@kernel.org \
--cc=daniel@makrotopia.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=horms@kernel.org \
--cc=jjohnson@kernel.org \
--cc=johannes@sipsolutions.net \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mmc@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=quic_bgodavar@quicinc.com \
--cc=quic_rjliao@quicinc.com \
--cc=robh@kernel.org \
--cc=saravanak@kernel.org \
--cc=srini@kernel.org \
--cc=ulfh@kernel.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