Allow a wider audience to test this pending series.
Use about to be submitted v3 which factors out block notification support.
Apart from dropping the no longer needed (and problematic) fallback for
for the 'partitions' node being present at the device parent there are
no intended functional changes.
As opening a block device as file is not supported yet in Kernel v6.6,
use the previous method as backporting seems a bit too involving.
Fixes: #15642
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
# CONFIG_BLK_DEV_UBLK is not set
# CONFIG_BLK_DEV_ZONED is not set
# CONFIG_BLK_INLINE_ENCRYPTION is not set
-# CONFIG_BLK_NVMEM is not set
+# CONFIG_BLOCK_NOTIFIERS is not set
# CONFIG_BLK_SED_OPAL is not set
# CONFIG_BLK_WBT is not set
CONFIG_BLOCK=y
# CONFIG_NVIDIA_CARMEL_CNP_ERRATUM is not set
# CONFIG_NVMEM is not set
# CONFIG_NVMEM_BCM_OCOTP is not set
+# CONFIG_NVMEM_BLOCK is not set
# CONFIG_NVMEM_IMX_OCOTP is not set
# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
+++ /dev/null
-From 9ffc1d7d73609a89eb264d6066340f8b7b3b0ebe Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 7 Aug 2023 21:19:45 +0100
-Subject: [PATCH 08/15] dt-bindings: block: add basic bindings for block
- devices
-
-Add bindings for block devices which are used to allow referencing
-nvmem bits on them.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- .../bindings/block/block-device.yaml | 22 ++++++++
- .../devicetree/bindings/block/partition.yaml | 50 +++++++++++++++++++
- .../devicetree/bindings/block/partitions.yaml | 20 ++++++++
- 3 files changed, 92 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
- create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
- create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/block-device.yaml
-@@ -0,0 +1,22 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/block-device.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: block storage device
-+
-+description: |
-+ This binding is generic and describes a block-oriented storage device.
-+
-+maintainers:
-+ - Daniel Golle <daniel@makrotopia.org>
-+
-+properties:
-+ partitions:
-+ $ref: /schemas/block/partitions.yaml
-+
-+ nvmem-layout:
-+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
-+
-+unevaluatedProperties: false
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/partition.yaml
-@@ -0,0 +1,50 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/partition.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Partition on a block device
-+
-+description: |
-+ This binding describes a partition on a block device.
-+ Partitions may be matched by a combination of partition number, name,
-+ and UUID.
-+
-+maintainers:
-+ - Daniel Golle <daniel@makrotopia.org>
-+
-+properties:
-+ $nodename:
-+ pattern: '^block-partition-.+$'
-+
-+ partnum:
-+ description:
-+ Matches partition by number if present.
-+
-+ partname:
-+ "$ref": "/schemas/types.yaml#/definitions/string"
-+ description:
-+ Matches partition by PARTNAME if present.
-+
-+ uuid:
-+ "$ref": "/schemas/types.yaml#/definitions/string"
-+ description:
-+ Matches partition by PARTUUID if present.
-+
-+ nvmem-layout:
-+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
-+ description:
-+ This container may reference an NVMEM layout parser.
-+
-+anyOf:
-+ - required:
-+ - partnum
-+
-+ - required:
-+ - partname
-+
-+ - required:
-+ - uuid
-+
-+unevaluatedProperties: false
---- /dev/null
-+++ b/Documentation/devicetree/bindings/block/partitions.yaml
-@@ -0,0 +1,20 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/block/partitions.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Partitions on block devices
-+
-+description: |
-+ This binding is generic and describes the content of the partitions container
-+ node.
-+
-+maintainers:
-+ - Daniel Golle <daniel@makrotopia.org>
-+
-+patternProperties:
-+ "^block-partition-.+$":
-+ $ref: partition.yaml
-+
-+unevaluatedProperties: false
+++ /dev/null
-From 614f4f6fdda09e30ecf7ef6c8091579db15018cb Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Fri, 21 Jul 2023 17:51:03 +0100
-Subject: [PATCH 09/15] block: partitions: populate fwnode
-
-Let block partitions to be represented by a firmware node and hence
-allow them to being referenced e.g. for use with blk-nvmem.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
-
---- a/block/partitions/core.c
-+++ b/block/partitions/core.c
-@@ -10,6 +10,8 @@
- #include <linux/ctype.h>
- #include <linux/vmalloc.h>
- #include <linux/raid/detect.h>
-+#include <linux/property.h>
-+
- #include "check.h"
-
- static int (*const check_part[])(struct parsed_partitions *) = {
-@@ -292,6 +294,43 @@ static ssize_t whole_disk_show(struct de
- }
- static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
-
-+static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
-+{
-+ struct fwnode_handle *fw_parts, *fw_part;
-+ struct device *ddev = disk_to_dev(bdev->bd_disk);
-+ const char *partname, *uuid;
-+ u32 partno;
-+
-+ fw_parts = device_get_named_child_node(ddev, "partitions");
-+ if (!fw_parts)
-+ fw_parts = device_get_named_child_node(ddev->parent, "partitions");
-+
-+ if (!fw_parts)
-+ return NULL;
-+
-+ fwnode_for_each_child_node(fw_parts, fw_part) {
-+ if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
-+ (!bdev->bd_meta_info || strncmp(uuid,
-+ bdev->bd_meta_info->uuid,
-+ PARTITION_META_INFO_UUIDLTH)))
-+ continue;
-+
-+ if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
-+ (!bdev->bd_meta_info || strncmp(partname,
-+ bdev->bd_meta_info->volname,
-+ PARTITION_META_INFO_VOLNAMELTH)))
-+ continue;
-+
-+ if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
-+ bdev->bd_partno != partno)
-+ continue;
-+
-+ return fw_part;
-+ }
-+
-+ return NULL;
-+}
-+
- /*
- * Must be called either with open_mutex held, before a disk can be opened or
- * after all disk users are gone.
-@@ -374,6 +413,8 @@ static struct block_device *add_partitio
- goto out_put;
- }
-
-+ device_set_node(pdev, find_partition_fwnode(bdev));
-+
- /* delay uevent until 'holders' subdir is created */
- dev_set_uevent_suppress(pdev, 1);
- err = device_add(pdev);
+++ /dev/null
-From 65f3ff9672ccd5ee78937047e7a2fc696eee1c8f Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Thu, 13 Jul 2023 04:07:16 +0100
-Subject: [PATCH 10/15] block: add new genhd flag GENHD_FL_NVMEM
-
-Add new flag to destinguish block devices which may act as an NVMEM
-provider.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- include/linux/blkdev.h | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -80,11 +80,13 @@ struct partition_meta_info {
- * ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
- * scan for partitions from add_disk, and users can't add partitions manually.
- *
-+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
- */
- enum {
- GENHD_FL_REMOVABLE = 1 << 0,
- GENHD_FL_HIDDEN = 1 << 1,
- GENHD_FL_NO_PART = 1 << 2,
-+ GENHD_FL_NVMEM = 1 << 3,
- };
-
- enum {
+++ /dev/null
-From b9936aa8a3775c2027f655d91a206d0e6e1c7ec0 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Tue, 11 Jul 2023 00:17:31 +0100
-Subject: [PATCH 11/15] block: implement NVMEM provider
-
-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.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- block/Kconfig | 9 +++
- block/Makefile | 1 +
- block/blk-nvmem.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 196 insertions(+)
- create mode 100644 block/blk-nvmem.c
-
---- a/block/Kconfig
-+++ b/block/Kconfig
-@@ -208,6 +208,15 @@ 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 prodivers,
-+ typically used with eMMC to store MAC addresses or Wi-Fi
-+ calibration data on embedded devices.
-+
- source "block/partitions/Kconfig"
-
- config BLK_MQ_PCI
---- a/block/Makefile
-+++ b/block/Makefile
-@@ -34,6 +34,7 @@ obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned
- obj-$(CONFIG_BLK_WBT) += blk-wbt.o
- obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
- obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-+obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
- obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
- obj-$(CONFIG_BLK_PM) += blk-pm.o
- obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
---- /dev/null
-+++ b/block/blk-nvmem.c
-@@ -0,0 +1,186 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * block device NVMEM provider
-+ *
-+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
-+ *
-+ * Useful on devices using a partition on an eMMC for MAC addresses or
-+ * Wi-Fi calibration EEPROM data.
-+ */
-+
-+#include "blk.h"
-+#include <linux/nvmem-provider.h>
-+#include <linux/of.h>
-+#include <linux/pagemap.h>
-+#include <linux/property.h>
-+
-+/* List of all NVMEM devices */
-+static LIST_HEAD(nvmem_devices);
-+static DEFINE_MUTEX(devices_mutex);
-+
-+struct blk_nvmem {
-+ struct nvmem_device *nvmem;
-+ struct block_device *bdev;
-+ struct list_head list;
-+};
-+
-+static int blk_nvmem_reg_read(void *priv, unsigned int from,
-+ void *val, size_t bytes)
-+{
-+ unsigned long offs = from & ~PAGE_MASK, to_read;
-+ pgoff_t f_index = from >> PAGE_SHIFT;
-+ struct address_space *mapping;
-+ struct blk_nvmem *bnv = priv;
-+ size_t bytes_left = bytes;
-+ struct folio *folio;
-+ void *p;
-+ int ret;
-+
-+ if (!bnv->bdev)
-+ return -ENODEV;
-+
-+ if (!bnv->bdev->bd_disk)
-+ return -EINVAL;
-+
-+ if (!bnv->bdev->bd_disk->fops)
-+ return -EIO;
-+
-+ if (!bnv->bdev->bd_disk->fops->open)
-+ return -EIO;
-+
-+ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
-+ if (ret)
-+ return ret;
-+
-+ mapping = bnv->bdev->bd_inode->i_mapping;
-+
-+ while (bytes_left) {
-+ folio = read_mapping_folio(mapping, f_index++, NULL);
-+ if (IS_ERR(folio)) {
-+ ret = PTR_ERR(folio);
-+ goto err_release_bdev;
-+ }
-+ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
-+ p = folio_address(folio) + offset_in_folio(folio, offs);
-+ memcpy(val, p, to_read);
-+ offs = 0;
-+ bytes_left -= to_read;
-+ val += to_read;
-+ folio_put(folio);
-+ }
-+
-+err_release_bdev:
-+ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk);
-+
-+ return ret;
-+}
-+
-+static int blk_nvmem_register(struct device *dev)
-+{
-+ struct device_node *np = dev_of_node(dev);
-+ struct block_device *bdev = dev_to_bdev(dev);
-+ struct nvmem_config config = {};
-+ struct blk_nvmem *bnv;
-+
-+ /* skip devices which do not have a device tree node */
-+ if (!np)
-+ return 0;
-+
-+ /* skip devices without an nvmem layout defined */
-+ if (!of_get_child_by_name(np, "nvmem-layout"))
-+ return 0;
-+
-+ /*
-+ * skip devices which don't have GENHD_FL_NVMEM set
-+ *
-+ * This flag is used for mtdblock and ubiblock devices because
-+ * both, MTD and UBI already implement their own NVMEM provider.
-+ * To avoid registering multiple NVMEM providers for the same
-+ * device node, don't register the block NVMEM provider for them.
-+ */
-+ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
-+ return 0;
-+
-+ /*
-+ * skip block device too large to be represented as NVMEM devices
-+ * which are using an 'int' as address
-+ */
-+ if (bdev_nr_bytes(bdev) > INT_MAX)
-+ return -EFBIG;
-+
-+ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
-+ if (!bnv)
-+ return -ENOMEM;
-+
-+ config.id = NVMEM_DEVID_NONE;
-+ config.dev = &bdev->bd_device;
-+ config.name = dev_name(&bdev->bd_device);
-+ config.owner = THIS_MODULE;
-+ config.priv = bnv;
-+ config.reg_read = blk_nvmem_reg_read;
-+ config.size = bdev_nr_bytes(bdev);
-+ config.word_size = 1;
-+ config.stride = 1;
-+ config.read_only = true;
-+ config.root_only = true;
-+ config.ignore_wp = true;
-+ config.of_node = to_of_node(dev->fwnode);
-+
-+ bnv->bdev = bdev;
-+ bnv->nvmem = nvmem_register(&config);
-+ if (IS_ERR(bnv->nvmem)) {
-+ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
-+ "Failed to register NVMEM device\n");
-+
-+ kfree(bnv);
-+ return PTR_ERR(bnv->nvmem);
-+ }
-+
-+ mutex_lock(&devices_mutex);
-+ list_add_tail(&bnv->list, &nvmem_devices);
-+ mutex_unlock(&devices_mutex);
-+
-+ return 0;
-+}
-+
-+static void blk_nvmem_unregister(struct device *dev)
-+{
-+ struct block_device *bdev = dev_to_bdev(dev);
-+ struct blk_nvmem *bnv_c, *bnv = NULL;
-+
-+ mutex_lock(&devices_mutex);
-+ list_for_each_entry(bnv_c, &nvmem_devices, list) {
-+ if (bnv_c->bdev == bdev) {
-+ bnv = bnv_c;
-+ break;
-+ }
-+ }
-+
-+ if (!bnv) {
-+ mutex_unlock(&devices_mutex);
-+ return;
-+ }
-+
-+ list_del(&bnv->list);
-+ mutex_unlock(&devices_mutex);
-+ nvmem_unregister(bnv->nvmem);
-+ kfree(bnv);
-+}
-+
-+static struct class_interface blk_nvmem_bus_interface __refdata = {
-+ .class = &block_class,
-+ .add_dev = &blk_nvmem_register,
-+ .remove_dev = &blk_nvmem_unregister,
-+};
-+
-+static int __init blk_nvmem_init(void)
-+{
-+ int ret;
-+
-+ ret = class_interface_register(&blk_nvmem_bus_interface);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+device_initcall(blk_nvmem_init);
+++ /dev/null
-From 86864bf8f40e84dc881c197ef470a88668329dbf Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 7 Aug 2023 21:21:45 +0100
-Subject: [PATCH 12/15] dt-bindings: mmc: mmc-card: add block device nodes
-
-Add nodes representing the block devices exposed by an MMC device
-including an example involving nvmem-cells.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- .../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
- 1 file changed, 45 insertions(+)
-
---- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
-+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
-@@ -26,6 +26,18 @@ properties:
- Use this to indicate that the mmc-card has a broken hpi
- implementation, and that hpi should not be used.
-
-+ block:
-+ $ref: /schemas/block/block-device.yaml#
-+ description:
-+ Represents the block storage provided by an SD card or the
-+ main hardware partition of an eMMC.
-+
-+patternProperties:
-+ '^boot[0-9]+':
-+ $ref: /schemas/block/block-device.yaml#
-+ description:
-+ Represents a boot hardware partition on an eMMC.
-+
- required:
- - compatible
- - reg
-@@ -42,6 +54,39 @@ examples:
- compatible = "mmc-card";
- reg = <0>;
- broken-hpi;
-+
-+ block {
-+ partitions {
-+ cal_data: block-partition-rf {
-+ partnum = <3>;
-+ partname = "rf";
-+
-+ nvmem-layout {
-+ compatible = "fixed-layout";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ eeprom@0 {
-+ reg = <0x0 0x1000>;
-+ };
-+ };
-+ };
-+ };
-+ };
-+
-+ boot1 {
-+ nvmem-layout {
-+ compatible = "fixed-layout";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ macaddr: macaddr@a {
-+ compatible = "mac-base";
-+ reg = <0xa 0x6>;
-+ #nvmem-cell-cells = <1>;
-+ };
-+ };
-+ };
- };
- };
-
+++ /dev/null
-From 644942a31719de674e2aa68f83d66bd8ae7e4fb7 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Thu, 13 Jul 2023 04:12:21 +0100
-Subject: [PATCH 13/15] mmc: core: set card fwnode_handle
-
-Set fwnode in case it isn't set yet and of_node is present.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/mmc/core/bus.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/mmc/core/bus.c
-+++ b/drivers/mmc/core/bus.c
-@@ -364,6 +364,8 @@ int mmc_add_card(struct mmc_card *card)
-
- mmc_add_card_debugfs(card);
- card->dev.of_node = mmc_of_find_child_device(card->host, 0);
-+ if (card->dev.of_node && !card->dev.fwnode)
-+ card->dev.fwnode = &card->dev.of_node->fwnode;
-
- device_enable_async_suspend(&card->dev);
-
+++ /dev/null
-From d9143f86330dd038fc48878558dd287ceee5d3d4 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Thu, 13 Jul 2023 04:13:04 +0100
-Subject: [PATCH 14/15] mmc: block: set fwnode of disk devices
-
-Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
-the mmc-card. This is done in preparation for having the eMMC act as
-NVMEM provider.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/mmc/core/block.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2463,6 +2463,8 @@ static struct mmc_blk_data *mmc_blk_allo
- int area_type,
- unsigned int part_type)
- {
-+ struct fwnode_handle *fwnode;
-+ struct device *ddev;
- struct mmc_blk_data *md;
- int devidx, ret;
- char cap_str[10];
-@@ -2559,6 +2561,13 @@ static struct mmc_blk_data *mmc_blk_allo
-
- blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);
-
-+ ddev = disk_to_dev(md->disk);
-+ fwnode = device_get_named_child_node(subname ? md->parent->parent :
-+ md->parent,
-+ subname ? subname : "block");
-+ if (fwnode)
-+ device_set_node(ddev, fwnode);
-+
- string_get_size((u64)size, 512, STRING_UNITS_2,
- cap_str, sizeof(cap_str));
- pr_info("%s: %s %s %s%s\n",
+++ /dev/null
-From 322035ab2b0113d98b6c0ea788d971e0df2952a4 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Thu, 20 Jul 2023 17:36:44 +0100
-Subject: [PATCH 15/15] mmc: block: set GENHD_FL_NVMEM
-
-Set flag to consider MMC block devices as NVMEM providers.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/mmc/core/block.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/mmc/core/block.c
-+++ b/drivers/mmc/core/block.c
-@@ -2517,6 +2517,7 @@ static struct mmc_blk_data *mmc_blk_allo
- md->disk->major = MMC_BLOCK_MAJOR;
- md->disk->minors = perdev_minors;
- md->disk->first_minor = devidx * perdev_minors;
-+ md->disk->flags = GENHD_FL_NVMEM;
- md->disk->fops = &mmc_bdops;
- md->disk->private_data = md;
- md->parent = parent;
--- /dev/null
+From 3245921a87154bdfbe7a55d743ea62dd559a8fb0 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:13:09 +0100
+Subject: [PATCH 1/9] dt-bindings: block: add basic bindings for block devices
+
+Add bindings for block devices which are used to allow referencing
+nvmem bits on them.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ .../bindings/block/block-device.yaml | 22 ++++++++
+ .../devicetree/bindings/block/partition.yaml | 51 +++++++++++++++++++
+ .../devicetree/bindings/block/partitions.yaml | 20 ++++++++
+ 3 files changed, 93 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
+ create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
+ create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/block-device.yaml
+@@ -0,0 +1,22 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/block-device.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: block storage device
++
++description: |
++ This binding is generic and describes a block-oriented storage device.
++
++maintainers:
++ - Daniel Golle <daniel@makrotopia.org>
++
++properties:
++ partitions:
++ $ref: /schemas/block/partitions.yaml
++
++ nvmem-layout:
++ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++
++unevaluatedProperties: false
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/partition.yaml
+@@ -0,0 +1,51 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/partition.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Partition on a block device
++
++description: |
++ This binding describes a partition on a block device.
++ Partitions may be matched by a combination of partition number, name,
++ and UUID.
++
++maintainers:
++ - Daniel Golle <daniel@makrotopia.org>
++
++properties:
++ $nodename:
++ pattern: '^block-partition-.+$'
++
++ partnum:
++ $ref: /schemas/types.yaml#/definitions/uint32
++ description:
++ Matches partition by number if present.
++
++ partname:
++ $ref: /schemas/types.yaml#/definitions/string
++ description:
++ Matches partition by PARTNAME if present.
++
++ partuuid:
++ $ref: /schemas/types.yaml#/definitions/string
++ description:
++ Matches partition by PARTUUID if present.
++
++ nvmem-layout:
++ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++ description:
++ This container may reference an NVMEM layout parser.
++
++anyOf:
++ - required:
++ - partnum
++
++ - required:
++ - partname
++
++ - required:
++ - partuuid
++
++unevaluatedProperties: false
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/partitions.yaml
+@@ -0,0 +1,20 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/partitions.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Partitions on block devices
++
++description: |
++ This binding is generic and describes the content of the partitions container
++ node.
++
++maintainers:
++ - Daniel Golle <daniel@makrotopia.org>
++
++patternProperties:
++ "^block-partition-.+$":
++ $ref: partition.yaml
++
++unevaluatedProperties: false
--- /dev/null
+From 7f4c9c534aabe1315669e076d3fe0af0fd374cda Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:13:19 +0100
+Subject: [PATCH 2/9] block: partitions: populate fwnode
+
+Let block partitions to be represented by a firmware node and hence
+allow them to being referenced e.g. for use with blk-nvmem.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -10,6 +10,8 @@
+ #include <linux/ctype.h>
+ #include <linux/vmalloc.h>
+ #include <linux/raid/detect.h>
++#include <linux/property.h>
++
+ #include "check.h"
+
+ static int (*const check_part[])(struct parsed_partitions *) = {
+@@ -292,6 +294,40 @@ static ssize_t whole_disk_show(struct de
+ }
+ static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
+
++static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
++{
++ struct fwnode_handle *fw_parts, *fw_part;
++ struct device *ddev = disk_to_dev(bdev->bd_disk);
++ const char *partname, *uuid;
++ u32 partno;
++
++ fw_parts = device_get_named_child_node(ddev, "partitions");
++ if (!fw_parts)
++ return NULL;
++
++ fwnode_for_each_child_node(fw_parts, fw_part) {
++ if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
++ (!bdev->bd_meta_info || strncmp(uuid,
++ bdev->bd_meta_info->uuid,
++ PARTITION_META_INFO_UUIDLTH)))
++ continue;
++
++ if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
++ (!bdev->bd_meta_info || strncmp(partname,
++ bdev->bd_meta_info->volname,
++ PARTITION_META_INFO_VOLNAMELTH)))
++ continue;
++
++ if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
++ bdev->bd_partno != partno)
++ continue;
++
++ return fw_part;
++ }
++
++ return NULL;
++}
++
+ /*
+ * Must be called either with open_mutex held, before a disk can be opened or
+ * after all disk users are gone.
+@@ -374,6 +410,8 @@ static struct block_device *add_partitio
+ goto out_put;
+ }
+
++ device_set_node(pdev, find_partition_fwnode(bdev));
++
+ /* delay uevent until 'holders' subdir is created */
+ dev_set_uevent_suppress(pdev, 1);
+ err = device_add(pdev);
--- /dev/null
+From e07ace307ce598847074a096f408bec0e3a392ed Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:14:34 +0100
+Subject: [PATCH 3/9] block: add support for notifications
+
+Add notifier block to notify other subsystems about the addition or
+removal of block devices.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ block/Kconfig | 6 +++
+ block/Makefile | 1 +
+ block/blk-notify.c | 88 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/blkdev.h | 8 ++++
+ 4 files changed, 103 insertions(+)
+ create mode 100644 block/blk-notify.c
+
+--- a/block/Kconfig
++++ b/block/Kconfig
+@@ -208,6 +208,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
+ by falling back to the kernel crypto API when inline
+ encryption hardware is not present.
+
++config BLOCK_NOTIFIERS
++ bool "Enable support for notifications in block layer"
++ help
++ Enable this option to provide notifiers for other subsystems
++ upon addition or removal of block devices.
++
+ source "block/partitions/Kconfig"
+
+ config BLK_MQ_PCI
+--- a/block/Makefile
++++ b/block/Makefile
+@@ -40,3 +40,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += b
+ blk-crypto-sysfs.o
+ obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
+ obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
++obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o
+--- /dev/null
++++ b/block/blk-notify.c
+@@ -0,0 +1,88 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Notifiers for addition and removal of block devices
++ *
++ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/notifier.h>
++
++#include "blk.h"
++
++struct blk_device_list {
++ struct device *dev;
++ struct list_head list;
++};
++
++static RAW_NOTIFIER_HEAD(blk_notifier_list);
++static DEFINE_MUTEX(blk_notifier_lock);
++static LIST_HEAD(blk_devices);
++
++void blk_register_notify(struct notifier_block *nb)
++{
++ struct blk_device_list *existing_blkdev;
++
++ mutex_lock(&blk_notifier_lock);
++ raw_notifier_chain_register(&blk_notifier_list, nb);
++
++ list_for_each_entry(existing_blkdev, &blk_devices, list)
++ nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev);
++
++ mutex_unlock(&blk_notifier_lock);
++}
++EXPORT_SYMBOL_GPL(blk_register_notify);
++
++void blk_unregister_notify(struct notifier_block *nb)
++{
++ mutex_lock(&blk_notifier_lock);
++ raw_notifier_chain_unregister(&blk_notifier_list, nb);
++ mutex_unlock(&blk_notifier_lock);
++}
++EXPORT_SYMBOL_GPL(blk_unregister_notify);
++
++static int blk_call_notifier_add(struct device *dev)
++{
++ struct blk_device_list *new_blkdev;
++
++ new_blkdev = kmalloc(sizeof(*new_blkdev), GFP_KERNEL);
++ if (!new_blkdev)
++ return -ENOMEM;
++
++ new_blkdev->dev = dev;
++ mutex_lock(&blk_notifier_lock);
++ list_add_tail(&new_blkdev->list, &blk_devices);
++ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, dev);
++ mutex_unlock(&blk_notifier_lock);
++
++ return 0;
++}
++
++static void blk_call_notifier_remove(struct device *dev)
++{
++ struct blk_device_list *old_blkdev, *tmp;
++
++ mutex_lock(&blk_notifier_lock);
++ list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) {
++ if (old_blkdev->dev != dev)
++ continue;
++
++ list_del(&old_blkdev->list);
++ kfree(old_blkdev);
++ }
++ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev);
++ mutex_unlock(&blk_notifier_lock);
++}
++
++static struct class_interface blk_notifications_bus_interface __refdata = {
++ .class = &block_class,
++ .add_dev = &blk_call_notifier_add,
++ .remove_dev = &blk_call_notifier_remove,
++};
++
++static int __init blk_notifications_init(void)
++{
++ return class_interface_register(&blk_notifications_bus_interface);
++}
++device_initcall(blk_notifications_init);
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1564,4 +1564,12 @@ struct io_comp_batch {
+
+ #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
+
++
++#ifdef CONFIG_BLOCK_NOTIFIERS
++#define BLK_DEVICE_ADD 1
++#define BLK_DEVICE_REMOVE 2
++void blk_register_notify(struct notifier_block *nb);
++void blk_unregister_notify(struct notifier_block *nb);
++#endif
++
+ #endif /* _LINUX_BLKDEV_H */
--- /dev/null
+From f4487fa1cb7e55b3c17a33f41b9c9d66f4f853b7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:14:49 +0100
+Subject: [PATCH 4/9] block: add new genhd flag GENHD_FL_NVMEM
+
+Add new flag to destinguish block devices which may act as an NVMEM
+provider.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ include/linux/blkdev.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -80,11 +80,13 @@ struct partition_meta_info {
+ * ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
+ * scan for partitions from add_disk, and users can't add partitions manually.
+ *
++ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
+ */
+ enum {
+ GENHD_FL_REMOVABLE = 1 << 0,
+ GENHD_FL_HIDDEN = 1 << 1,
+ GENHD_FL_NO_PART = 1 << 2,
++ GENHD_FL_NVMEM = 1 << 3,
+ };
+
+ enum {
--- /dev/null
+From 9703951cdfe868b130e64d6122420396c2807be8 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:15:02 +0100
+Subject: [PATCH 5/9] nvmem: implement block NVMEM provider
+
+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 any block device or partition in Device Tree to
+allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/nvmem/Kconfig | 11 +++
+ drivers/nvmem/Makefile | 2 +
+ drivers/nvmem/block.c | 197 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 210 insertions(+)
+ create mode 100644 drivers/nvmem/block.c
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES
+ This driver can also be built as a module. If so, the module will
+ be called nvmem-apple-efuses.
+
++config NVMEM_BLOCK
++ tristate "Block device NVMEM provider"
++ depends on BLOCK
++ depends on OF
++ depends on NVMEM
++ select BLOCK_NOTIFIERS
++ help
++ Allow block devices (or partitions) to act as NVMEM prodivers,
++ typically used with eMMC to store MAC addresses or Wi-Fi
++ calibration data on embedded devices.
++
+ config NVMEM_BCM_OCOTP
+ tristate "Broadcom On-Chip OTP Controller support"
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
+--- a/drivers/nvmem/Makefile
++++ b/drivers/nvmem/Makefile
+@@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvme
+ nvmem-apple-efuses-y := apple-efuses.o
+ obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o
+ nvmem-bcm-ocotp-y := bcm-ocotp.o
++obj-$(CONFIG_NVMEM_BLOCK) += nvmem-block.o
++nvmem-block-y := block.o
+ obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
+ nvmem_brcm_nvram-y := brcm_nvram.o
+ obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o
+--- /dev/null
++++ b/drivers/nvmem/block.c
+@@ -0,0 +1,208 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * block device NVMEM provider
++ *
++ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
++ *
++ * Useful on devices using a partition on an eMMC for MAC addresses or
++ * Wi-Fi calibration EEPROM data.
++ */
++
++#include <linux/blkdev.h>
++#include <linux/nvmem-provider.h>
++#include <linux/of.h>
++#include <linux/pagemap.h>
++#include <linux/property.h>
++
++/* List of all NVMEM devices */
++static LIST_HEAD(nvmem_devices);
++static DEFINE_MUTEX(devices_mutex);
++
++struct blk_nvmem {
++ struct nvmem_device *nvmem;
++ struct block_device *bdev;
++ struct list_head list;
++};
++
++static int blk_nvmem_reg_read(void *priv, unsigned int from,
++ void *val, size_t bytes)
++{
++ unsigned long offs = from & ~PAGE_MASK, to_read;
++ pgoff_t f_index = from >> PAGE_SHIFT;
++ struct address_space *mapping;
++ struct blk_nvmem *bnv = priv;
++ size_t bytes_left = bytes;
++ struct folio *folio;
++ void *p;
++ int ret;
++
++ if (!bnv->bdev)
++ return -ENODEV;
++
++ if (!bnv->bdev->bd_disk)
++ return -EINVAL;
++
++ if (!bnv->bdev->bd_disk->fops)
++ return -EIO;
++
++ if (!bnv->bdev->bd_disk->fops->open)
++ return -EIO;
++
++ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
++ if (ret)
++ return ret;
++
++ mapping = bnv->bdev->bd_inode->i_mapping;
++
++ while (bytes_left) {
++ folio = read_mapping_folio(mapping, f_index++, NULL);
++ if (IS_ERR(folio)) {
++ ret = PTR_ERR(folio);
++ goto err_release_bdev;
++ }
++ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
++ p = folio_address(folio) + offset_in_folio(folio, offs);
++ memcpy(val, p, to_read);
++ offs = 0;
++ bytes_left -= to_read;
++ val += to_read;
++ folio_put(folio);
++ }
++
++err_release_bdev:
++ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk);
++
++ return ret;
++}
++
++static int blk_nvmem_register(struct device *dev)
++{
++ struct device_node *np = dev_of_node(dev);
++ struct block_device *bdev = dev_to_bdev(dev);
++ struct nvmem_config config = {};
++ struct blk_nvmem *bnv;
++
++ /* skip devices which do not have a device tree node */
++ if (!np)
++ return 0;
++
++ /* skip devices without an nvmem layout defined */
++ if (!of_get_child_by_name(np, "nvmem-layout"))
++ return 0;
++
++ /*
++ * skip devices which don't have GENHD_FL_NVMEM set
++ *
++ * This flag is used for mtdblock and ubiblock devices because
++ * both, MTD and UBI already implement their own NVMEM provider.
++ * To avoid registering multiple NVMEM providers for the same
++ * device node, don't register the block NVMEM provider for them.
++ */
++ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
++ return 0;
++
++ /*
++ * skip block device too large to be represented as NVMEM devices
++ * which are using an 'int' as address
++ */
++ if (bdev_nr_bytes(bdev) > INT_MAX)
++ return -EFBIG;
++
++ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
++ if (!bnv)
++ return -ENOMEM;
++
++ config.id = NVMEM_DEVID_NONE;
++ config.dev = &bdev->bd_device;
++ config.name = dev_name(&bdev->bd_device);
++ config.owner = THIS_MODULE;
++ config.priv = bnv;
++ config.reg_read = blk_nvmem_reg_read;
++ config.size = bdev_nr_bytes(bdev);
++ config.word_size = 1;
++ config.stride = 1;
++ config.read_only = true;
++ config.root_only = true;
++ config.ignore_wp = true;
++ config.of_node = to_of_node(dev->fwnode);
++
++ bnv->bdev = bdev;
++ bnv->nvmem = nvmem_register(&config);
++ if (IS_ERR(bnv->nvmem)) {
++ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
++ "Failed to register NVMEM device\n");
++
++ kfree(bnv);
++ return PTR_ERR(bnv->nvmem);
++ }
++
++ mutex_lock(&devices_mutex);
++ list_add_tail(&bnv->list, &nvmem_devices);
++ mutex_unlock(&devices_mutex);
++
++ return 0;
++}
++
++static void blk_nvmem_unregister(struct device *dev)
++{
++ struct block_device *bdev = dev_to_bdev(dev);
++ struct blk_nvmem *bnv_c, *bnv = NULL;
++
++ mutex_lock(&devices_mutex);
++ list_for_each_entry(bnv_c, &nvmem_devices, list) {
++ if (bnv_c->bdev == bdev) {
++ bnv = bnv_c;
++ break;
++ }
++ }
++
++ if (!bnv) {
++ mutex_unlock(&devices_mutex);
++ return;
++ }
++
++ list_del(&bnv->list);
++ mutex_unlock(&devices_mutex);
++ nvmem_unregister(bnv->nvmem);
++ kfree(bnv);
++}
++
++static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj)
++{
++ struct device *dev = (struct device *)obj;
++
++ switch (code) {
++ case BLK_DEVICE_ADD:
++ return blk_nvmem_register(dev);
++ case BLK_DEVICE_REMOVE:
++ blk_nvmem_unregister(dev);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static struct notifier_block blk_nvmem_notifier = {
++ .notifier_call = blk_nvmem_handler,
++};
++
++static int __init blk_nvmem_init(void)
++{
++ blk_register_notify(&blk_nvmem_notifier);
++
++ return 0;
++}
++
++static void __exit blk_nvmem_exit(void)
++{
++ blk_unregister_notify(&blk_nvmem_notifier);
++}
++
++module_init(blk_nvmem_init);
++module_exit(blk_nvmem_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
++MODULE_DESCRIPTION("block device NVMEM provider");
--- /dev/null
+From f7ec19b34d1b7e934a58ceb102369bbd30b2631d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:15:11 +0100
+Subject: [PATCH 6/9] dt-bindings: mmc: mmc-card: add block device nodes
+
+Add nodes representing the block devices exposed by an MMC device
+including an example involving nvmem-cells.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ .../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
++++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+@@ -26,6 +26,18 @@ properties:
+ Use this to indicate that the mmc-card has a broken hpi
+ implementation, and that hpi should not be used.
+
++ block:
++ $ref: /schemas/block/block-device.yaml#
++ description:
++ Represents the block storage provided by an SD card or the
++ main hardware partition of an eMMC.
++
++patternProperties:
++ '^boot[0-9]+':
++ $ref: /schemas/block/block-device.yaml#
++ description:
++ Represents a boot hardware partition on an eMMC.
++
+ required:
+ - compatible
+ - reg
+@@ -42,6 +54,39 @@ examples:
+ compatible = "mmc-card";
+ reg = <0>;
+ broken-hpi;
++
++ block {
++ partitions {
++ cal_data: block-partition-rf {
++ partnum = <3>;
++ partname = "rf";
++
++ nvmem-layout {
++ compatible = "fixed-layout";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ eeprom@0 {
++ reg = <0x0 0x1000>;
++ };
++ };
++ };
++ };
++ };
++
++ boot1 {
++ nvmem-layout {
++ compatible = "fixed-layout";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ macaddr: macaddr@a {
++ compatible = "mac-base";
++ reg = <0xa 0x6>;
++ #nvmem-cell-cells = <1>;
++ };
++ };
++ };
+ };
+ };
+
--- /dev/null
+From 043c4f88476cc0f29c9bf82a8a516f58d848e1cd Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:15:25 +0100
+Subject: [PATCH 7/9] mmc: core: set card fwnode_handle
+
+Set fwnode in case it isn't set yet and of_node is present.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mmc/core/bus.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/mmc/core/bus.c
++++ b/drivers/mmc/core/bus.c
+@@ -364,6 +364,8 @@ int mmc_add_card(struct mmc_card *card)
+
+ mmc_add_card_debugfs(card);
+ card->dev.of_node = mmc_of_find_child_device(card->host, 0);
++ if (card->dev.of_node && !card->dev.fwnode)
++ card->dev.fwnode = &card->dev.of_node->fwnode;
+
+ device_enable_async_suspend(&card->dev);
+
--- /dev/null
+From ef3e38fec26901b71975d7e810a2df6b8bd54a8e Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:15:36 +0100
+Subject: [PATCH 8/9] mmc: block: set fwnode of disk devices
+
+Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
+the mmc-card. This is done in preparation for having the eMMC act as
+NVMEM provider.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mmc/core/block.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2463,6 +2463,7 @@ static struct mmc_blk_data *mmc_blk_allo
+ int area_type,
+ unsigned int part_type)
+ {
++ struct fwnode_handle *fwnode;
+ struct mmc_blk_data *md;
+ int devidx, ret;
+ char cap_str[10];
+@@ -2559,6 +2560,12 @@ static struct mmc_blk_data *mmc_blk_allo
+
+ blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);
+
++ fwnode = device_get_named_child_node(subname ? md->parent->parent :
++ md->parent,
++ subname ? subname : "block");
++ if (fwnode)
++ device_set_node(disk_to_dev(md->disk), fwnode);
++
+ string_get_size((u64)size, 512, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ pr_info("%s: %s %s %s%s\n",
--- /dev/null
+From 7903b50441000365a6fe5badb39735889f562252 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 30 May 2024 03:15:46 +0100
+Subject: [PATCH 9/9] mmc: block: set GENHD_FL_NVMEM
+
+Set flag to consider MMC block devices as NVMEM providers.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mmc/core/block.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2516,6 +2516,7 @@ static struct mmc_blk_data *mmc_blk_allo
+ md->disk->major = MMC_BLOCK_MAJOR;
+ md->disk->minors = perdev_minors;
+ md->disk->first_minor = devidx * perdev_minors;
++ md->disk->flags = GENHD_FL_NVMEM;
+ md->disk->fops = &mmc_bdops;
+ md->disk->private_data = md;
+ md->parent = parent;
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_MQ_PCI=y
-CONFIG_BLK_NVMEM=y
CONFIG_BLK_PM=y
+CONFIG_BLOCK_NOTIFIERS=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_BUFFER_HEAD=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_NVMEM=y
+CONFIG_NVMEM_BLOCK=y
CONFIG_NVMEM_LAYOUTS=y
CONFIG_NVMEM_MTK_EFUSE=y
CONFIG_NVMEM_SYSFS=y
#ifdef CONFIG_SGI_PARTITION
sgi_partition,
#endif
-@@ -433,6 +439,11 @@ static struct block_device *add_partitio
+@@ -430,6 +436,11 @@ static struct block_device *add_partitio
goto out_del;
}
/* everything is up and running, commence */
err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
if (err)
-@@ -625,6 +636,11 @@ static bool blk_add_partition(struct gen
+@@ -622,6 +633,11 @@ static bool blk_add_partition(struct gen
(state->parts[p].flags & ADDPART_FLAG_RAID))
md_autodetect_dev(part->bd_dev);