From c9acd03f45e7c1a479f89c0de9898a8f6c8a293a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 4 Dec 2023 23:48:40 +0000 Subject: [PATCH] kernel: import pending patches adding support for NVMEM on UBI and MMC Similar to supporting nvmem-layouts on MTD devices, also allow referencing UBI and MMC devices in DT. Signed-off-by: Daniel Golle --- ...111-MMC-added-alternative-MMC-driver.patch | 6 +- target/linux/generic/config-6.1 | 2 + ...dings-mtd-add-basic-bindings-for-UBI.patch | 121 ++++++++ ...ubi-volume-allow-UBI-volumes-to-prov.patch | 48 ++++ ...e-notifier-to-create-ubiblock-from-p.patch | 225 +++++++++++++++ ...0-04-mtd-ubi-attach-from-device-tree.patch | 264 ++++++++++++++++++ ...e-pre-removal-notification-for-UBI-v.patch | 226 +++++++++++++++ ...6-mtd-ubi-populate-ubi-volume-fwnode.patch | 65 +++++ ...provide-NVMEM-layer-over-UBI-volumes.patch | 243 ++++++++++++++++ ...k-add-basic-bindings-for-block-devic.patch | 120 ++++++++ ...-09-block-partitions-populate-fwnode.patch | 77 +++++ ...ck-add-new-genhd-flag-GENHD_FL_NVMEM.patch | 29 ++ ...50-11-block-implement-NVMEM-provider.patch | 235 ++++++++++++++++ ...-mmc-mmc-card-add-block-device-nodes.patch | 74 +++++ ...0-13-mmc-core-set-card-fwnode_handle.patch | 23 ++ ...mmc-block-set-fwnode-of-disk-devices.patch | 38 +++ .../450-15-mmc-block-set-GENHD_FL_NVMEM.patch | 22 ++ ...mtd-device-named-ubi-or-data-on-boot.patch | 17 +- ...to-create-ubiblock-device-for-rootfs.patch | 76 ++--- ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 4 +- .../494-mtd-ubi-add-EOF-marker-support.patch | 2 +- .../041-block-fit-partition-parser.patch | 15 +- 22 files changed, 1876 insertions(+), 56 deletions(-) create mode 100644 target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch create mode 100644 target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch create mode 100644 target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch create mode 100644 target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch create mode 100644 target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch create mode 100644 target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch create mode 100644 target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch create mode 100644 target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch create mode 100644 target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch create mode 100644 target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch create mode 100644 target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch create mode 100644 target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch create mode 100644 target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch create mode 100644 target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch create mode 100644 target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch diff --git a/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch index 09402fbc351..22799956a06 100644 --- a/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch +++ b/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch @@ -266,7 +266,7 @@ Signed-off-by: Phil Elwell 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, -@@ -3000,6 +3007,8 @@ static int mmc_blk_probe(struct mmc_card +@@ -3009,6 +3016,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 /* * Check that the card supports the command class(es) we need. -@@ -3007,7 +3016,16 @@ static int mmc_blk_probe(struct mmc_card +@@ -3016,7 +3025,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 card->complete_wq = alloc_workqueue("mmc_complete", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); -@@ -3022,6 +3040,17 @@ static int mmc_blk_probe(struct mmc_card +@@ -3031,6 +3049,17 @@ static int mmc_blk_probe(struct mmc_card goto out_free; } diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index 279cf0bf14f..e97d00101ad 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -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 @@ -4036,6 +4037,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 index 00000000000..063d3fa79c9 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch @@ -0,0 +1,121 @@ +From ffbbe7d66872ff8957dad2136133e28a1fd5d437 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + .../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 ++ ++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 ++ ++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 index 00000000000..823c8e83b71 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch @@ -0,0 +1,48 @@ +From e4dad3aa5c3ab9c553555dd23c0b85f725f2eb51 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + .../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 index 00000000000..eda3b108da3 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch @@ -0,0 +1,225 @@ +From e5cf19bd8204925f3bd2067df9e867313eac388b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +Signed-off-by: Daniel Golle +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 00000000000..6e10e5ebed4 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch @@ -0,0 +1,264 @@ +From 471a17d8d1b838092d1a76e48cdce8b5b67ff809 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 + #include + #include ++#include + #include + #include + #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 index 00000000000..d5da37b8562 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch @@ -0,0 +1,226 @@ +From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 '//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 index 00000000000..13227669654 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch @@ -0,0 +1,65 @@ +From 3a041ee543cdf2e707a1dd72946cd6a583509b28 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 index 00000000000..9e6fbea38cf --- /dev/null +++ b/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch @@ -0,0 +1,243 @@ +From 7eb6666348f3f2d1f7308c712fa5903cbe189401 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 ++ */ ++ ++/* UBI NVMEM provider */ ++#include "ubi.h" ++#include ++#include ++ ++/* 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 index 00000000000..d0727faf3dc --- /dev/null +++ b/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch @@ -0,0 +1,120 @@ +From 9ffc1d7d73609a89eb264d6066340f8b7b3b0ebe Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + .../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 ++ ++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 ++ ++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 ++ ++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 index 00000000000..8aa5cba6788 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch @@ -0,0 +1,77 @@ +From 614f4f6fdda09e30ecf7ef6c8091579db15018cb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 + #include + #include ++#include ++ + #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 index 00000000000..4cbec14f5c9 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch @@ -0,0 +1,29 @@ +From 65f3ff9672ccd5ee78937047e7a2fc696eee1c8f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 index 00000000000..e18b0c3a5c7 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch @@ -0,0 +1,235 @@ +From b9936aa8a3775c2027f655d91a206d0e6e1c7ec0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 ++ * ++ * Useful on devices using a partition on an eMMC for MAC addresses or ++ * Wi-Fi calibration EEPROM data. ++ */ ++ ++#include "blk.h" ++#include ++#include ++#include ++#include ++ ++/* 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 index 00000000000..77c9bf91a54 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch @@ -0,0 +1,74 @@ +From 86864bf8f40e84dc881c197ef470a88668329dbf Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + .../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 index 00000000000..fada2804379 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch @@ -0,0 +1,23 @@ +From 644942a31719de674e2aa68f83d66bd8ae7e4fb7 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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 index 00000000000..0ce0a43f6ce --- /dev/null +++ b/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch @@ -0,0 +1,38 @@ +From d9143f86330dd038fc48878558dd287ceee5d3d4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + drivers/mmc/core/block.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2444,6 +2444,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]; +@@ -2540,6 +2542,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 index 00000000000..7fa3440e9b6 --- /dev/null +++ b/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch @@ -0,0 +1,22 @@ +From 322035ab2b0113d98b6c0ea788d971e0df2952a4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + drivers/mmc/core/block.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2498,6 +2498,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; diff --git a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch index 765eecd9d71..2eccb9d3bbb 100644 --- a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch +++ b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -8,10 +8,11 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c -@@ -1212,6 +1212,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 + put_mtd_device(mtd); +} + - static int __init ubi_init(void) + static int __init ubi_init_attach(void) { int err, i, k; -@@ -1296,6 +1363,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 + !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: diff --git a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch index 17e8d8bedb6..a43da2a5725 100644 --- a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch +++ b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -8,8 +8,8 @@ Signed-off-by: Daniel Golle --- 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 + 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, diff --git a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch index e3493ef19ef..5357c7e15d7 100644 --- a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch +++ b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c -@@ -42,6 +42,7 @@ +@@ -43,6 +43,7 @@ #include #include #include @@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle #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); diff --git a/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch index 413431755f1..fc481462212 100644 --- a/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch +++ b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch @@ -50,7 +50,7 @@ Signed-off-by: Gabor Juhos 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; diff --git a/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch b/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch index 1258f64722a..a7a47a27e9f 100644 --- a/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch +++ b/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch @@ -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 +@@ -11,6 +11,9 @@ #include #include + #include +#ifdef CONFIG_FIT_PARTITION +#include +#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) -@@ -585,6 +597,11 @@ static bool blk_add_partition(struct gen +@@ -626,6 +637,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; } -- 2.30.2