kernel: import pending patches adding support for NVMEM on UBI and MMC
authorDaniel Golle <daniel@makrotopia.org>
Mon, 4 Dec 2023 23:48:40 +0000 (23:48 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 15 Feb 2024 19:06:36 +0000 (19:06 +0000)
Similar to supporting nvmem-layouts on MTD devices, also allow referencing
UBI and MMC devices in DT.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
22 files changed:
target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch
target/linux/generic/config-6.1
target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch
target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch

index 476a3caf3cd0f75d2012d694c2700e475cff2336..693ed2b6d1e30c9ab603b71eb2fec8a9490f7061 100644 (file)
@@ -266,7 +266,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
  static inline int mmc_blk_part_switch(struct mmc_card *card,
                                      unsigned int part_type);
  static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
-@@ -3040,6 +3047,8 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3049,6 +3056,8 @@ static int mmc_blk_probe(struct mmc_card
  {
        struct mmc_blk_data *md;
        int ret = 0;
@@ -275,7 +275,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
  
        /*
         * Check that the card supports the command class(es) we need.
-@@ -3047,7 +3056,16 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3056,7 +3065,16 @@ static int mmc_blk_probe(struct mmc_card
        if (!(card->csd.cmdclass & CCC_BLOCK_READ))
                return -ENODEV;
  
@@ -293,7 +293,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
  
        card->complete_wq = alloc_workqueue("mmc_complete",
                                        WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
-@@ -3062,6 +3080,17 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3071,6 +3089,17 @@ static int mmc_blk_probe(struct mmc_card
                goto out_free;
        }
  
index 30bda17d17fb6ac3bf6fa609210dcb9e4fd8d970..ce1bfcd5bf5cd2cb2b4fc8ee3e41f42e83e95ac4 100644 (file)
@@ -730,6 +730,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_ZONED is not set
 # CONFIG_BLK_INLINE_ENCRYPTION is not set
+# CONFIG_BLK_NVMEM is not set
 # CONFIG_BLK_SED_OPAL is not set
 # CONFIG_BLK_WBT is not set
 CONFIG_BLOCK=y
@@ -4037,6 +4038,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y
 # CONFIG_MTD_UBI is not set
 # CONFIG_MTD_UBI_FASTMAP is not set
 # CONFIG_MTD_UBI_GLUEBI is not set
+# CONFIG_MTD_UBI_NVMEM is not set
 # CONFIG_MTD_UIMAGE_SPLIT is not set
 # CONFIG_MTD_VIRT_CONCAT is not set
 # CONFIG_MTK_DEVAPC is not set
diff --git a/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch b/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch
new file mode 100644 (file)
index 0000000..063d3fa
--- /dev/null
@@ -0,0 +1,121 @@
+From ffbbe7d66872ff8957dad2136133e28a1fd5d437 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 7 Aug 2023 22:51:05 +0100
+Subject: [PATCH 01/15] dt-bindings: mtd: add basic bindings for UBI
+
+Add basic bindings for UBI devices and volumes.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ .../bindings/mtd/partitions/linux,ubi.yaml    | 65 +++++++++++++++++++
+ .../bindings/mtd/partitions/ubi-volume.yaml   | 35 ++++++++++
+ 2 files changed, 100 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+@@ -0,0 +1,65 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Unsorted Block Images
++
++description: |
++  UBI ("Unsorted Block Images") is a volume management system for raw
++  flash devices which manages multiple logical volumes on a single
++  physical flash device and spreads the I/O load (i.e wear-leveling)
++  across the whole flash chip.
++
++maintainers:
++  - Daniel Golle <daniel@makrotopia.org>
++
++allOf:
++  - $ref: partition.yaml#
++
++properties:
++  compatible:
++    const: linux,ubi
++
++  volumes:
++    type: object
++    description: UBI Volumes
++
++    patternProperties:
++      "^ubi-volume-.*$":
++        $ref: /schemas/mtd/partitions/ubi-volume.yaml#
++
++    unevaluatedProperties: false
++
++required:
++  - compatible
++
++unevaluatedProperties: false
++
++examples:
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            reg = <0x0 0x100000>;
++            label = "bootloader";
++            read-only;
++        };
++
++        partition@100000 {
++            reg = <0x100000 0x1ff00000>;
++            label = "ubi";
++            compatible = "linux,ubi";
++
++            volumes {
++                ubi-volume-caldata {
++                    volid = <2>;
++                    volname = "rf";
++                };
++            };
++        };
++    };
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+@@ -0,0 +1,35 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: UBI volume
++
++description: |
++  This binding describes a single UBI volume. Volumes can be matches either
++  by their ID or their name, or both.
++
++maintainers:
++  - Daniel Golle <daniel@makrotopia.org>
++
++properties:
++  volid:
++    $ref: "/schemas/types.yaml#/definitions/uint32"
++    description:
++      Match UBI volume ID
++
++  volname:
++    $ref: "/schemas/types.yaml#/definitions/string"
++    description:
++      Match UBI volume ID
++
++anyOf:
++  - required:
++    - volid
++
++  - required:
++    - volname
++
++# This is a generic file other binding inherit from and extend
++additionalProperties: true
diff --git a/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch b/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch
new file mode 100644 (file)
index 0000000..823c8e8
--- /dev/null
@@ -0,0 +1,48 @@
+From e4dad3aa5c3ab9c553555dd23c0b85f725f2eb51 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 7 Aug 2023 22:53:01 +0100
+Subject: [PATCH 02/15] dt-bindings: mtd: ubi-volume: allow UBI volumes to
+ provide NVMEM
+
+UBI volumes may be used to contain NVMEM bits, typically device MAC
+addresses or wireless radio calibration data.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ .../devicetree/bindings/mtd/partitions/linux,ubi.yaml  | 10 ++++++++++
+ .../devicetree/bindings/mtd/partitions/ubi-volume.yaml |  5 +++++
+ 2 files changed, 15 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
++++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+@@ -59,6 +59,16 @@ examples:
+                 ubi-volume-caldata {
+                     volid = <2>;
+                     volname = "rf";
++
++                    nvmem-layout {
++                        compatible = "fixed-layout";
++                        #address-cells = <1>;
++                        #size-cells = <1>;
++
++                        eeprom@0 {
++                            reg = <0x0 0x1000>;
++                        };
++                    };
+                 };
+             };
+         };
+--- a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
++++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+@@ -24,6 +24,11 @@ properties:
+     description:
+       Match UBI volume ID
++  nvmem-layout:
++    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++    description:
++      This container may reference an NVMEM layout parser.
++
+ anyOf:
+   - required:
+     - volid
diff --git a/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch b/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch
new file mode 100644 (file)
index 0000000..eda3b10
--- /dev/null
@@ -0,0 +1,225 @@
+From e5cf19bd8204925f3bd2067df9e867313eac388b Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 1 May 2023 11:57:51 +0100
+Subject: [PATCH 03/15] mtd: ubi: block: use notifier to create ubiblock from
+ parameter
+
+Use UBI_VOLUME_ADDED notification to create ubiblock device specified
+on kernel cmdline or module parameter.
+This makes thing more simple and has the advantage that ubiblock devices
+on volumes which are not present at the time the ubi module is probed
+will still be created.
+
+Suggested-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 154 ++++++++++++++++++++++------------------
+ 1 file changed, 85 insertions(+), 69 deletions(-)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -33,6 +33,7 @@
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/mutex.h>
++#include <linux/namei.h>
+ #include <linux/slab.h>
+ #include <linux/mtd/ubi.h>
+ #include <linux/workqueue.h>
+@@ -67,10 +68,10 @@ struct ubiblock_pdu {
+ };
+ /* Numbers of elements set in the @ubiblock_param array */
+-static int ubiblock_devs __initdata;
++static int ubiblock_devs;
+ /* MTD devices specification parameters */
+-static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
++static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
+ struct ubiblock {
+       struct ubi_volume_desc *desc;
+@@ -504,7 +505,7 @@ int ubiblock_remove(struct ubi_volume_in
+       }
+       /* Found a device, let's lock it so we can check if it's busy */
+-      mutex_lock(&dev->dev_mutex);
++      mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
+       if (dev->refcnt > 0) {
+               ret = -EBUSY;
+               goto out_unlock_dev;
+@@ -567,6 +568,85 @@ static int ubiblock_resize(struct ubi_vo
+       return 0;
+ }
++static bool
++match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
++{
++      int err, len;
++      struct path path;
++      struct kstat stat;
++
++      if (ubi_num == -1) {
++              /* No ubi num, name must be a vol device path */
++              err = kern_path(name, LOOKUP_FOLLOW, &path);
++              if (err)
++                      return false;
++
++              err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
++              path_put(&path);
++              if (err)
++                      return false;
++
++              if (!S_ISCHR(stat.mode))
++                      return false;
++
++              if (vi->ubi_num != ubi_major2num(MAJOR(stat.rdev)))
++                      return false;
++
++              if (vi->vol_id != MINOR(stat.rdev) - 1)
++                      return false;
++
++              return true;
++      }
++
++      if (vol_id == -1) {
++              if (vi->ubi_num != ubi_num)
++                      return false;
++
++              len = strnlen(name, UBI_VOL_NAME_MAX + 1);
++              if (len < 1 || vi->name_len != len)
++                      return false;
++
++              if (strcmp(name, vi->name))
++                      return false;
++
++              return true;
++      }
++
++      if (vi->ubi_num != ubi_num)
++              return false;
++
++      if (vi->vol_id != vol_id)
++              return false;
++
++      return true;
++}
++
++static void
++ubiblock_create_from_param(struct ubi_volume_info *vi)
++{
++      int i, ret = 0;
++      struct ubiblock_param *p;
++
++      /*
++       * Iterate over ubiblock cmdline parameters. If a parameter matches the
++       * newly added volume create the ubiblock device for it.
++       */
++      for (i = 0; i < ubiblock_devs; i++) {
++              p = &ubiblock_param[i];
++
++              if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
++                      continue;
++
++              ret = ubiblock_create(vi);
++              if (ret) {
++                      pr_err(
++                             "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
++                             vi->name, p->ubi_num, p->vol_id, ret);
++              }
++              break;
++      }
++}
++
+ static int ubiblock_notify(struct notifier_block *nb,
+                        unsigned long notification_type, void *ns_ptr)
+ {
+@@ -574,10 +654,7 @@ static int ubiblock_notify(struct notifi
+       switch (notification_type) {
+       case UBI_VOLUME_ADDED:
+-              /*
+-               * We want to enforce explicit block device creation for
+-               * volumes, so when a volume is added we do nothing.
+-               */
++              ubiblock_create_from_param(&nt->vi);
+               break;
+       case UBI_VOLUME_REMOVED:
+               ubiblock_remove(&nt->vi);
+@@ -603,56 +680,6 @@ static struct notifier_block ubiblock_no
+       .notifier_call = ubiblock_notify,
+ };
+-static struct ubi_volume_desc * __init
+-open_volume_desc(const char *name, int ubi_num, int vol_id)
+-{
+-      if (ubi_num == -1)
+-              /* No ubi num, name must be a vol device path */
+-              return ubi_open_volume_path(name, UBI_READONLY);
+-      else if (vol_id == -1)
+-              /* No vol_id, must be vol_name */
+-              return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
+-      else
+-              return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
+-}
+-
+-static void __init ubiblock_create_from_param(void)
+-{
+-      int i, ret = 0;
+-      struct ubiblock_param *p;
+-      struct ubi_volume_desc *desc;
+-      struct ubi_volume_info vi;
+-
+-      /*
+-       * If there is an error creating one of the ubiblocks, continue on to
+-       * create the following ubiblocks. This helps in a circumstance where
+-       * the kernel command-line specifies multiple block devices and some
+-       * may be broken, but we still want the working ones to come up.
+-       */
+-      for (i = 0; i < ubiblock_devs; i++) {
+-              p = &ubiblock_param[i];
+-
+-              desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
+-              if (IS_ERR(desc)) {
+-                      pr_err(
+-                             "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
+-                             p->ubi_num, p->vol_id, PTR_ERR(desc));
+-                      continue;
+-              }
+-
+-              ubi_get_volume_info(desc, &vi);
+-              ubi_close_volume(desc);
+-
+-              ret = ubiblock_create(&vi);
+-              if (ret) {
+-                      pr_err(
+-                             "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
+-                             vi.name, p->ubi_num, p->vol_id, ret);
+-                      continue;
+-              }
+-      }
+-}
+-
+ static void ubiblock_remove_all(void)
+ {
+       struct ubiblock *next;
+@@ -678,18 +705,7 @@ int __init ubiblock_init(void)
+       if (ubiblock_major < 0)
+               return ubiblock_major;
+-      /*
+-       * Attach block devices from 'block=' module param.
+-       * Even if one block device in the param list fails to come up,
+-       * still allow the module to load and leave any others up.
+-       */
+-      ubiblock_create_from_param();
+-
+-      /*
+-       * Block devices are only created upon user requests, so we ignore
+-       * existing volumes.
+-       */
+-      ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
++      ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
+       if (ret)
+               goto err_unreg;
+       return 0;
diff --git a/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch b/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch
new file mode 100644 (file)
index 0000000..6e10e5e
--- /dev/null
@@ -0,0 +1,264 @@
+From 471a17d8d1b838092d1a76e48cdce8b5b67ff809 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 27 Nov 2023 01:54:28 +0000
+Subject: [PATCH 04/15] mtd: ubi: attach from device tree
+
+Introduce device tree compatible 'linux,ubi' and attach compatible MTD
+devices using the MTD add notifier. This is needed for a UBI device to
+be available early at boot (and not only after late_initcall), so
+volumes on them can be used eg. as NVMEM providers for other drivers.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 146 ++++++++++++++++++++++++++++------------
+ drivers/mtd/ubi/cdev.c  |   2 +-
+ drivers/mtd/ubi/ubi.h   |   2 +-
+ 3 files changed, 106 insertions(+), 44 deletions(-)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -27,6 +27,7 @@
+ #include <linux/log2.h>
+ #include <linux/kthread.h>
+ #include <linux/kernel.h>
++#include <linux/of.h>
+ #include <linux/slab.h>
+ #include <linux/major.h>
+ #include "ubi.h"
+@@ -1071,6 +1072,7 @@ out_free:
+  * ubi_detach_mtd_dev - detach an MTD device.
+  * @ubi_num: UBI device number to detach from
+  * @anyway: detach MTD even if device reference count is not zero
++ * @have_lock: called by MTD notifier holding mtd_table_mutex
+  *
+  * This function destroys an UBI device number @ubi_num and detaches the
+  * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+@@ -1080,7 +1082,7 @@ out_free:
+  * Note, the invocations of this function has to be serialized by the
+  * @ubi_devices_mutex.
+  */
+-int ubi_detach_mtd_dev(int ubi_num, int anyway)
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
+ {
+       struct ubi_device *ubi;
+@@ -1136,7 +1138,11 @@ int ubi_detach_mtd_dev(int ubi_num, int
+       vfree(ubi->peb_buf);
+       vfree(ubi->fm_buf);
+       ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
+-      put_mtd_device(ubi->mtd);
++      if (have_lock)
++              __put_mtd_device(ubi->mtd);
++      else
++              put_mtd_device(ubi->mtd);
++
+       put_device(&ubi->dev);
+       return 0;
+ }
+@@ -1213,43 +1219,43 @@ static struct mtd_info * __init open_mtd
+       return mtd;
+ }
+-static int __init ubi_init(void)
++static void ubi_notify_add(struct mtd_info *mtd)
+ {
+-      int err, i, k;
++      struct device_node *np = mtd_get_of_node(mtd);
++      int err;
+-      /* Ensure that EC and VID headers have correct size */
+-      BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+-      BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
++      if (!of_device_is_compatible(np, "linux,ubi"))
++              return;
+-      if (mtd_devs > UBI_MAX_DEVICES) {
+-              pr_err("UBI error: too many MTD devices, maximum is %d\n",
+-                     UBI_MAX_DEVICES);
+-              return -EINVAL;
+-      }
++      /*
++       * we are already holding &mtd_table_mutex, but still need
++       * to bump refcount
++       */
++      err = __get_mtd_device(mtd);
++      if (err)
++              return;
+-      /* Create base sysfs directory and sysfs files */
+-      err = class_register(&ubi_class);
++      /* called while holding mtd_table_mutex */
++      mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
++      err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
++      mutex_unlock(&ubi_devices_mutex);
+       if (err < 0)
+-              return err;
+-
+-      err = misc_register(&ubi_ctrl_cdev);
+-      if (err) {
+-              pr_err("UBI error: cannot register device\n");
+-              goto out;
+-      }
++              __put_mtd_device(mtd);
++}
+-      ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+-                                            sizeof(struct ubi_wl_entry),
+-                                            0, 0, NULL);
+-      if (!ubi_wl_entry_slab) {
+-              err = -ENOMEM;
+-              goto out_dev_unreg;
+-      }
++static void ubi_notify_remove(struct mtd_info *mtd)
++{
++      WARN(1, "mtd%d removed despite UBI still being attached", mtd->index);
++}
+-      err = ubi_debugfs_init();
+-      if (err)
+-              goto out_slab;
++static struct mtd_notifier ubi_mtd_notifier = {
++      .add = ubi_notify_add,
++      .remove = ubi_notify_remove,
++};
++static int __init ubi_init_attach(void)
++{
++      int err, i, k;
+       /* Attach MTD devices */
+       for (i = 0; i < mtd_devs; i++) {
+@@ -1297,25 +1303,79 @@ static int __init ubi_init(void)
+               }
+       }
++      return 0;
++
++out_detach:
++      for (k = 0; k < i; k++)
++              if (ubi_devices[k]) {
++                      mutex_lock(&ubi_devices_mutex);
++                      ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1, false);
++                      mutex_unlock(&ubi_devices_mutex);
++              }
++      return err;
++}
++#ifndef CONFIG_MTD_UBI_MODULE
++late_initcall(ubi_init_attach);
++#endif
++
++static int __init ubi_init(void)
++{
++      int err;
++
++      /* Ensure that EC and VID headers have correct size */
++      BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
++      BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
++
++      if (mtd_devs > UBI_MAX_DEVICES) {
++              pr_err("UBI error: too many MTD devices, maximum is %d\n",
++                     UBI_MAX_DEVICES);
++              return -EINVAL;
++      }
++
++      /* Create base sysfs directory and sysfs files */
++      err = class_register(&ubi_class);
++      if (err < 0)
++              return err;
++
++      err = misc_register(&ubi_ctrl_cdev);
++      if (err) {
++              pr_err("UBI error: cannot register device\n");
++              goto out;
++      }
++
++      ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
++                                            sizeof(struct ubi_wl_entry),
++                                            0, 0, NULL);
++      if (!ubi_wl_entry_slab) {
++              err = -ENOMEM;
++              goto out_dev_unreg;
++      }
++
++      err = ubi_debugfs_init();
++      if (err)
++              goto out_slab;
++
+       err = ubiblock_init();
+       if (err) {
+               pr_err("UBI error: block: cannot initialize, error %d\n", err);
+               /* See comment above re-ubi_is_module(). */
+               if (ubi_is_module())
+-                      goto out_detach;
++                      goto out_slab;
++      }
++
++      register_mtd_user(&ubi_mtd_notifier);
++
++      if (ubi_is_module()) {
++              err = ubi_init_attach();
++              if (err)
++                      goto out_mtd_notifier;
+       }
+       return 0;
+-out_detach:
+-      for (k = 0; k < i; k++)
+-              if (ubi_devices[k]) {
+-                      mutex_lock(&ubi_devices_mutex);
+-                      ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+-                      mutex_unlock(&ubi_devices_mutex);
+-              }
+-      ubi_debugfs_exit();
++out_mtd_notifier:
++      unregister_mtd_user(&ubi_mtd_notifier);
+ out_slab:
+       kmem_cache_destroy(ubi_wl_entry_slab);
+ out_dev_unreg:
+@@ -1325,18 +1385,20 @@ out:
+       pr_err("UBI error: cannot initialize UBI, error %d\n", err);
+       return err;
+ }
+-late_initcall(ubi_init);
++device_initcall(ubi_init);
++
+ static void __exit ubi_exit(void)
+ {
+       int i;
+       ubiblock_exit();
++      unregister_mtd_user(&ubi_mtd_notifier);
+       for (i = 0; i < UBI_MAX_DEVICES; i++)
+               if (ubi_devices[i]) {
+                       mutex_lock(&ubi_devices_mutex);
+-                      ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
++                      ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, false);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       ubi_debugfs_exit();
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -1065,7 +1065,7 @@ static long ctrl_cdev_ioctl(struct file
+               }
+               mutex_lock(&ubi_devices_mutex);
+-              err = ubi_detach_mtd_dev(ubi_num, 0);
++              err = ubi_detach_mtd_dev(ubi_num, 0, false);
+               mutex_unlock(&ubi_devices_mutex);
+               break;
+       }
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -939,7 +939,7 @@ int ubi_io_write_vid_hdr(struct ubi_devi
+ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
+                      int vid_hdr_offset, int max_beb_per1024,
+                      bool disable_fm);
+-int ubi_detach_mtd_dev(int ubi_num, int anyway);
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock);
+ struct ubi_device *ubi_get_device(int ubi_num);
+ void ubi_put_device(struct ubi_device *ubi);
+ struct ubi_device *ubi_get_by_major(int major);
diff --git a/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch b/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch
new file mode 100644 (file)
index 0000000..d5da37b
--- /dev/null
@@ -0,0 +1,226 @@
+From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 8 Jun 2023 17:18:09 +0100
+Subject: [PATCH 05/15] mtd: ubi: introduce pre-removal notification for UBI
+ volumes
+
+Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
+that a volume is just about to be removed.
+This is needed because users (such as the NVMEM subsystem) expect that
+at the time their removal function is called, the parenting device is
+still available (for removal of sysfs nodes, for example, in case of
+NVMEM which otherwise WARNs on volume removal).
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
+ drivers/mtd/ubi/build.c | 20 +++++++++++++++-----
+ drivers/mtd/ubi/kapi.c  |  2 +-
+ drivers/mtd/ubi/ubi.h   |  2 ++
+ drivers/mtd/ubi/vmt.c   | 17 +++++++++++++++--
+ include/linux/mtd/ubi.h |  2 ++
+ 6 files changed, 61 insertions(+), 8 deletions(-)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -568,6 +568,29 @@ static int ubiblock_resize(struct ubi_vo
+       return 0;
+ }
++static int ubiblock_shutdown(struct ubi_volume_info *vi)
++{
++      struct ubiblock *dev;
++      struct gendisk *disk;
++      int ret = 0;
++
++      mutex_lock(&devices_mutex);
++      dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
++      if (!dev) {
++              ret = -ENODEV;
++              goto out_unlock;
++      }
++      disk = dev->gd;
++
++out_unlock:
++      mutex_unlock(&devices_mutex);
++
++      if (!ret)
++              blk_mark_disk_dead(disk);
++
++      return ret;
++};
++
+ static bool
+ match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
+ {
+@@ -659,6 +682,9 @@ static int ubiblock_notify(struct notifi
+       case UBI_VOLUME_REMOVED:
+               ubiblock_remove(&nt->vi);
+               break;
++      case UBI_VOLUME_SHUTDOWN:
++              ubiblock_shutdown(&nt->vi);
++              break;
+       case UBI_VOLUME_RESIZED:
+               ubiblock_resize(&nt->vi);
+               break;
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -89,7 +89,7 @@ static struct ubi_device *ubi_devices[UB
+ /* Serializes UBI devices creations and removals */
+ DEFINE_MUTEX(ubi_devices_mutex);
+-/* Protects @ubi_devices and @ubi->ref_count */
++/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
+ static DEFINE_SPINLOCK(ubi_devices_lock);
+ /* "Show" method for files in '/<sysfs>/class/ubi/' */
+@@ -258,6 +258,9 @@ struct ubi_device *ubi_get_device(int ub
+       spin_lock(&ubi_devices_lock);
+       ubi = ubi_devices[ubi_num];
++      if (ubi && ubi->is_dead)
++              ubi = NULL;
++
+       if (ubi) {
+               ubi_assert(ubi->ref_count >= 0);
+               ubi->ref_count += 1;
+@@ -295,7 +298,7 @@ struct ubi_device *ubi_get_by_major(int
+       spin_lock(&ubi_devices_lock);
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               ubi = ubi_devices[i];
+-              if (ubi && MAJOR(ubi->cdev.dev) == major) {
++              if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_assert(ubi->ref_count >= 0);
+                       ubi->ref_count += 1;
+                       get_device(&ubi->dev);
+@@ -324,7 +327,7 @@ int ubi_major2num(int major)
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               struct ubi_device *ubi = ubi_devices[i];
+-              if (ubi && MAJOR(ubi->cdev.dev) == major) {
++              if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_num = ubi->ubi_num;
+                       break;
+               }
+@@ -511,7 +514,7 @@ static void ubi_free_volumes_from(struct
+       int i;
+       for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+-              if (!ubi->volumes[i])
++              if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
+                       continue;
+               ubi_eba_replace_table(ubi->volumes[i], NULL);
+               ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
+@@ -1094,10 +1097,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
+               return -EINVAL;
+       spin_lock(&ubi_devices_lock);
+-      put_device(&ubi->dev);
+       ubi->ref_count -= 1;
+       if (ubi->ref_count) {
+               if (!anyway) {
++                      ubi->ref_count += 1;
+                       spin_unlock(&ubi_devices_lock);
+                       return -EBUSY;
+               }
+@@ -1105,6 +1108,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
+               ubi_err(ubi, "%s reference count %d, destroy anyway",
+                       ubi->ubi_name, ubi->ref_count);
+       }
++      ubi->is_dead = true;
++      spin_unlock(&ubi_devices_lock);
++
++      ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
++
++      spin_lock(&ubi_devices_lock);
++      put_device(&ubi->dev);
+       ubi_devices[ubi_num] = NULL;
+       spin_unlock(&ubi_devices_lock);
+--- a/drivers/mtd/ubi/kapi.c
++++ b/drivers/mtd/ubi/kapi.c
+@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
+       spin_lock(&ubi->volumes_lock);
+       vol = ubi->volumes[vol_id];
+-      if (!vol)
++      if (!vol || vol->is_dead)
+               goto out_unlock;
+       err = -EBUSY;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -345,6 +345,7 @@ struct ubi_volume {
+       int writers;
+       int exclusive;
+       int metaonly;
++      bool is_dead;
+       int reserved_pebs;
+       int vol_type;
+@@ -564,6 +565,7 @@ struct ubi_device {
+       spinlock_t volumes_lock;
+       int ref_count;
+       int image_seq;
++      bool is_dead;
+       int rsvd_pebs;
+       int avail_pebs;
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
+       struct ubi_device *ubi = vol->ubi;
+       spin_lock(&ubi->volumes_lock);
+-      if (!ubi->volumes[vol->vol_id]) {
++      if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
+               spin_unlock(&ubi->volumes_lock);
+               return -ENODEV;
+       }
+@@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
+       /* Ensure that the name is unique */
+       for (i = 0; i < ubi->vtbl_slots; i++)
+-              if (ubi->volumes[i] &&
++              if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
+                   ubi->volumes[i]->name_len == req->name_len &&
+                   !strcmp(ubi->volumes[i]->name, req->name)) {
+                       ubi_err(ubi, "volume \"%s\" exists (ID %d)",
+@@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
+               err = -EBUSY;
+               goto out_unlock;
+       }
++
++      /*
++       * Mark volume as dead at this point to prevent that anyone
++       * can take a reference to the volume from now on.
++       * This is necessary as we have to release the spinlock before
++       * calling ubi_volume_notify.
++       */
++      vol->is_dead = true;
++      spin_unlock(&ubi->volumes_lock);
++
++      ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
++
++      spin_lock(&ubi->volumes_lock);
+       ubi->volumes[vol_id] = NULL;
+       spin_unlock(&ubi->volumes_lock);
+--- a/include/linux/mtd/ubi.h
++++ b/include/linux/mtd/ubi.h
+@@ -192,6 +192,7 @@ struct ubi_device_info {
+  *                    or a volume was removed)
+  * @UBI_VOLUME_RESIZED: a volume has been re-sized
+  * @UBI_VOLUME_RENAMED: a volume has been re-named
++ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
+  * @UBI_VOLUME_UPDATED: data has been written to a volume
+  *
+  * These constants define which type of event has happened when a volume
+@@ -202,6 +203,7 @@ enum {
+       UBI_VOLUME_REMOVED,
+       UBI_VOLUME_RESIZED,
+       UBI_VOLUME_RENAMED,
++      UBI_VOLUME_SHUTDOWN,
+       UBI_VOLUME_UPDATED,
+ };
diff --git a/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch b/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch
new file mode 100644 (file)
index 0000000..1322766
--- /dev/null
@@ -0,0 +1,65 @@
+From 3a041ee543cdf2e707a1dd72946cd6a583509b28 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 21 Jul 2023 19:26:37 +0100
+Subject: [PATCH 06/15] mtd: ubi: populate ubi volume fwnode
+
+Look for the 'volumes' subnode of an MTD partition attached to a UBI
+device and attach matching child nodes to UBI volumes.
+This allows UBI volumes to be referenced in device tree, e.g. for use
+as NVMEM providers.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/vmt.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -124,6 +124,31 @@ static void vol_release(struct device *d
+       kfree(vol);
+ }
++static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
++{
++      struct fwnode_handle *fw_vols, *fw_vol;
++      const char *volname;
++      u32 volid;
++
++      fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
++      if (!fw_vols)
++              return NULL;
++
++      fwnode_for_each_child_node(fw_vols, fw_vol) {
++              if (!fwnode_property_read_string(fw_vol, "volname", &volname) &&
++                  strncmp(volname, vol->name, vol->name_len))
++                      continue;
++
++              if (!fwnode_property_read_u32(fw_vol, "volid", &volid) &&
++                  vol->vol_id != volid)
++                      continue;
++
++              return fw_vol;
++      }
++
++      return NULL;
++}
++
+ /**
+  * ubi_create_volume - create volume.
+  * @ubi: UBI device description object
+@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device
+       vol->name_len  = req->name_len;
+       memcpy(vol->name, req->name, vol->name_len);
+       vol->ubi = ubi;
++      device_set_node(&vol->dev, find_volume_fwnode(vol));
+       /*
+        * Finish all pending erases because there may be some LEBs belonging
+@@ -605,6 +631,7 @@ int ubi_add_volume(struct ubi_device *ub
+       vol->dev.class = &ubi_class;
+       vol->dev.groups = volume_dev_groups;
+       dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
++      device_set_node(&vol->dev, find_volume_fwnode(vol));
+       err = device_register(&vol->dev);
+       if (err) {
+               cdev_del(&vol->cdev);
diff --git a/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch b/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch
new file mode 100644 (file)
index 0000000..9e6fbea
--- /dev/null
@@ -0,0 +1,243 @@
+From 7eb6666348f3f2d1f7308c712fa5903cbe189401 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 8 Jun 2023 17:22:04 +0100
+Subject: [PATCH 07/15] mtd: ubi: provide NVMEM layer over UBI volumes
+
+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
+
+--- 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
+--- a/drivers/mtd/ubi/Makefile
++++ b/drivers/mtd/ubi/Makefile
+@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap
+ ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
+ obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
++obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
+--- /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");
diff --git a/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch b/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch
new file mode 100644 (file)
index 0000000..d0727fa
--- /dev/null
@@ -0,0 +1,120 @@
+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
diff --git a/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch b/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch
new file mode 100644 (file)
index 0000000..8aa5cba
--- /dev/null
@@ -0,0 +1,77 @@
+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 (*check_part[])(struct parsed_partitions *) = {
+@@ -298,6 +300,43 @@ static ssize_t whole_disk_show(struct de
+ }
+ static 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.
+@@ -380,6 +419,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);
diff --git a/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch b/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch
new file mode 100644 (file)
index 0000000..4cbec14
--- /dev/null
@@ -0,0 +1,29 @@
+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
+@@ -87,11 +87,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 {
diff --git a/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch b/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch
new file mode 100644 (file)
index 0000000..e18b0c3
--- /dev/null
@@ -0,0 +1,235 @@
+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
+@@ -203,6 +203,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 BLOCK_COMPAT
+--- a/block/Makefile
++++ b/block/Makefile
+@@ -35,6 +35,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, FMODE_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, FMODE_READ);
++
++      return ret;
++}
++
++static int blk_nvmem_register(struct device *dev, struct class_interface *iface)
++{
++      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 class_interface *iface)
++{
++      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);
diff --git a/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch b/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch
new file mode 100644 (file)
index 0000000..77c9bf9
--- /dev/null
@@ -0,0 +1,74 @@
+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>;
++                    };
++                };
++            };
+         };
+     };
diff --git a/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch b/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch
new file mode 100644 (file)
index 0000000..fada280
--- /dev/null
@@ -0,0 +1,23 @@
+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
+@@ -363,6 +363,8 @@ int mmc_add_card(struct mmc_card *card)
+       mmc_add_card_debugfs(card);
+ #endif
+       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);
diff --git a/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch b/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch
new file mode 100644 (file)
index 0000000..d033abb
--- /dev/null
@@ -0,0 +1,38 @@
+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
+@@ -2484,6 +2484,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];
+@@ -2580,6 +2582,12 @@ 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");
++      ddev->fwnode = fwnode;
++
+       string_get_size((u64)size, 512, STRING_UNITS_2,
+                       cap_str, sizeof(cap_str));
+       pr_info("%s: %s %s %s %s\n",
diff --git a/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch b/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch
new file mode 100644 (file)
index 0000000..d76e7b2
--- /dev/null
@@ -0,0 +1,22 @@
+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
+@@ -2538,6 +2538,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;
index 2601281bf7b7e1d123c265ec6bb4ffcafb261e65..2eccb9d3bbb513ec02d0b2f21f48995b09b71495 100644 (file)
@@ -8,10 +8,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 
 --- a/drivers/mtd/ubi/build.c
 +++ b/drivers/mtd/ubi/build.c
-@@ -1213,6 +1213,73 @@ static struct mtd_info * __init open_mtd
-       return mtd;
- }
+@@ -1263,6 +1263,74 @@ static struct mtd_notifier ubi_mtd_notif
+       .remove = ubi_notify_remove,
+ };
  
++
 +/*
 + * This function tries attaching mtd partitions named either "ubi" or "data"
 + * during boot.
@@ -79,10 +80,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 +      put_mtd_device(mtd);
 +}
 +
- static int __init ubi_init(void)
+ static int __init ubi_init_attach(void)
  {
        int err, i, k;
-@@ -1297,6 +1364,12 @@ static int __init ubi_init(void)
+@@ -1313,6 +1381,12 @@ static int __init ubi_init_attach(void)
                }
        }
  
@@ -92,6 +93,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 +          !ubi_is_module() && !mtd_devs)
 +              ubi_auto_attach();
 +
-       err = ubiblock_init();
-       if (err) {
-               pr_err("UBI error: block: cannot initialize, error %d\n", err);
+       return 0;
+ out_detach:
index 17e8d8bedb6c163415ac8bb62c0160aec2d67986..a43da2a57259a96a23c59da1e3de97407a9af8ad 100644 (file)
@@ -8,8 +8,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -653,6 +653,47 @@ static void __init ubiblock_create_from_
-       }
+@@ -644,10 +644,47 @@ match_volume_desc(struct ubi_volume_info
+       return true;
  }
  
 +#define UBIFS_NODE_MAGIC  0x06101831
@@ -24,46 +24,54 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 +      return magic == UBIFS_NODE_MAGIC;
 +}
 +
-+static void __init ubiblock_create_auto_rootfs(void)
++static void __init ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
 +{
-+      int ubi_num, ret, is_ubifs;
++      int ret, is_ubifs;
 +      struct ubi_volume_desc *desc;
-+      struct ubi_volume_info vi;
 +
-+      for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
-+              desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
-+              if (IS_ERR(desc))
-+                      desc = ubi_open_volume_nm(ubi_num, "fit", UBI_READONLY);;
++      if (strcmp(vi->name, "rootfs") &&
++          strcmp(vi->name, "fit"))
++              return;
 +
-+              if (IS_ERR(desc))
-+                      continue;
++      desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY);
++      if (IS_ERR(desc))
++              return;
 +
-+              ubi_get_volume_info(desc, &vi);
-+              is_ubifs = ubi_vol_is_ubifs(desc);
-+              ubi_close_volume(desc);
-+              if (is_ubifs)
-+                      break;
++      is_ubifs = ubi_vol_is_ubifs(desc);
++      ubi_close_volume(desc);
++      if (is_ubifs)
++              return;
 +
-+              ret = ubiblock_create(&vi);
-+              if (ret)
-+                      pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
-+                              vi.name, ret);
-+              /* always break if we get here */
-+              break;
-+      }
++      ret = ubiblock_create(vi);
++      if (ret)
++              pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
++                      vi->name, ret);
 +}
 +
- static void ubiblock_remove_all(void)
+ static void
+ ubiblock_create_from_param(struct ubi_volume_info *vi)
  {
-       struct ubiblock *next;
-@@ -685,6 +726,10 @@ int __init ubiblock_init(void)
-        */
-       ubiblock_create_from_param();
+       int i, ret = 0;
++      bool got_param = false;
+       struct ubiblock_param *p;
  
-+      /* auto-attach "rootfs" volume if existing and non-ubifs */
-+      if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
-+              ubiblock_create_auto_rootfs();
-+
        /*
-        * Block devices are only created upon user requests, so we ignore
-        * existing volumes.
+@@ -660,6 +697,7 @@ ubiblock_create_from_param(struct ubi_vo
+               if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
+                       continue;
++              got_param = true;
+               ret = ubiblock_create(vi);
+               if (ret) {
+                       pr_err(
+@@ -668,6 +706,10 @@ ubiblock_create_from_param(struct ubi_vo
+               }
+               break;
+       }
++
++      /* auto-attach "rootfs" volume if existing and non-ubifs */
++      if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
++              ubiblock_create_auto_rootfs(vi);
+ }
+ static int ubiblock_notify(struct notifier_block *nb,
index e3493ef19ef8ca9f49ad3e2f1dce348cd78ef3d4..5357c7e15d7b184625106d294df80545180aeb37 100644 (file)
@@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -42,6 +42,7 @@
+@@ -43,6 +43,7 @@
  #include <linux/scatterlist.h>
  #include <linux/idr.h>
  #include <asm/div64.h>
@@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  
  #include "ubi-media.h"
  #include "ubi.h"
-@@ -459,6 +460,15 @@ int ubiblock_create(struct ubi_volume_in
+@@ -460,6 +461,15 @@ int ubiblock_create(struct ubi_volume_in
        dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
                 dev->ubi_num, dev->vol_id, vi->name);
        mutex_unlock(&devices_mutex);
index 413431755f1d2c9ee31b4cd19cf334c6f1ae0a36..fc481462212cea54a57001c69b9040b52952d5f2 100644 (file)
@@ -50,7 +50,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
                break;
 --- a/drivers/mtd/ubi/ubi.h
 +++ b/drivers/mtd/ubi/ubi.h
-@@ -778,6 +778,7 @@ struct ubi_attach_info {
+@@ -780,6 +780,7 @@ struct ubi_attach_info {
        int mean_ec;
        uint64_t ec_sum;
        int ec_count;
index 3e45646fdb7bb50dddb1ef25b0862bb4a17cf39d..bb87c20a91e15e12c6511b136945060ff4ab2b45 100644 (file)
@@ -72,18 +72,17 @@ Subject: [PATCH] kernel: add block fit partition parser
 +int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain);
 --- a/block/partitions/core.c
 +++ b/block/partitions/core.c
-@@ -10,6 +10,10 @@
- #include <linux/ctype.h>
+@@ -11,6 +11,9 @@
  #include <linux/vmalloc.h>
  #include <linux/raid/detect.h>
+ #include <linux/property.h>
 +#ifdef CONFIG_FIT_PARTITION
 +#include <linux/root_dev.h>
 +#endif
-+
  #include "check.h"
  
- static int (*check_part[])(struct parsed_partitions *) = {
-@@ -46,6 +50,9 @@ static int (*check_part[])(struct parsed
+@@ -48,6 +51,9 @@ static int (*check_part[])(struct parsed
  #ifdef CONFIG_EFI_PARTITION
        efi_partition,          /* this must come before msdos */
  #endif
@@ -93,7 +92,7 @@ Subject: [PATCH] kernel: add block fit partition parser
  #ifdef CONFIG_SGI_PARTITION
        sgi_partition,
  #endif
-@@ -398,6 +405,11 @@ static struct block_device *add_partitio
+@@ -439,6 +445,11 @@ static struct block_device *add_partitio
                        goto out_del;
        }
  
@@ -105,7 +104,7 @@ Subject: [PATCH] kernel: add block fit partition parser
        /* everything is up and running, commence */
        err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
        if (err)
-@@ -590,6 +602,11 @@ static bool blk_add_partition(struct gen
+@@ -631,6 +642,11 @@ static bool blk_add_partition(struct gen
            (state->parts[p].flags & ADDPART_FLAG_RAID))
                md_autodetect_dev(part->bd_dev);
  
@@ -194,7 +193,7 @@ Subject: [PATCH] kernel: add block fit partition parser
        set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -431,7 +431,9 @@ int ubiblock_create(struct ubi_volume_in
+@@ -432,7 +432,9 @@ int ubiblock_create(struct ubi_volume_in
                ret = -ENODEV;
                goto out_cleanup_disk;
        }