From: Daniel Golle Date: Fri, 14 Jun 2024 15:24:12 +0000 (+0100) Subject: generic: 6.6: move NVMEM-on-UBI patches from pending to backports X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=4fd4be6bbe90b141ff64220165783b8b671dfddf;p=openwrt%2Fstaging%2Fansuel.git generic: 6.6: move NVMEM-on-UBI patches from pending to backports The series was merged for Linux v6.9, so move it to backports. Signed-off-by: Daniel Golle --- diff --git a/target/linux/generic/backport-6.6/401-v6.9-dt-bindings-mtd-add-basic-bindings-for-UBI.patch b/target/linux/generic/backport-6.6/401-v6.9-dt-bindings-mtd-add-basic-bindings-for-UBI.patch new file mode 100644 index 0000000000..811994861c --- /dev/null +++ b/target/linux/generic/backport-6.6/401-v6.9-dt-bindings-mtd-add-basic-bindings-for-UBI.patch @@ -0,0 +1,123 @@ +From 25d88bfd35bac3196eafa666e3b05033b46ffa21 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:32:00 +0000 +Subject: [PATCH 1/8] dt-bindings: mtd: add basic bindings for UBI + +Add basic bindings for UBI devices and volumes. + +Signed-off-by: Daniel Golle +Reviewed-by: Rob Herring +Signed-off-by: Richard Weinberger +--- + .../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/backport-6.6/402-v6.9-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch b/target/linux/generic/backport-6.6/402-v6.9-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch new file mode 100644 index 0000000000..a3943387fb --- /dev/null +++ b/target/linux/generic/backport-6.6/402-v6.9-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch @@ -0,0 +1,50 @@ +From 95b113222b5164ac0887eb5c514ff3970a0136f0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:32:11 +0000 +Subject: [PATCH 2/8] 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 +Reviewed-by: Rob Herring +Signed-off-by: Richard Weinberger +--- + .../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/backport-6.6/403-v6.9-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch b/target/linux/generic/backport-6.6/403-v6.9-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch new file mode 100644 index 0000000000..f89330cd10 --- /dev/null +++ b/target/linux/generic/backport-6.6/403-v6.9-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch @@ -0,0 +1,285 @@ +From 2bba1cdcfcd2907d0696cc0139f1bd078d36ee81 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:32:35 +0000 +Subject: [PATCH 3/8] 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 +Signed-off-by: Richard Weinberger +--- + drivers/mtd/ubi/block.c | 136 ++++++++++++++++++++-------------------- + drivers/mtd/ubi/kapi.c | 54 +++++++++++----- + drivers/mtd/ubi/ubi.h | 1 + + 3 files changed, 106 insertions(+), 85 deletions(-) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -65,10 +65,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; +@@ -532,6 +532,70 @@ 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, cur_ubi_num, cur_vol_id; ++ ++ if (ubi_num == -1) { ++ /* No ubi num, name must be a vol device path */ ++ err = ubi_get_num_by_path(name, &cur_ubi_num, &cur_vol_id); ++ if (err || vi->ubi_num != cur_ubi_num || vi->vol_id != cur_vol_id) ++ return false; ++ ++ return true; ++ } ++ ++ if (vol_id == -1) { ++ /* Got ubi_num, but no vol_id, name must be volume name */ ++ 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) + { +@@ -539,10 +603,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); +@@ -568,56 +629,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; +@@ -643,18 +654,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; +--- a/drivers/mtd/ubi/kapi.c ++++ b/drivers/mtd/ubi/kapi.c +@@ -280,6 +280,41 @@ struct ubi_volume_desc *ubi_open_volume_ + EXPORT_SYMBOL_GPL(ubi_open_volume_nm); + + /** ++ * ubi_get_num_by_path - get UBI device and volume number from device path ++ * @pathname: volume character device node path ++ * @ubi_num: pointer to UBI device number to be set ++ * @vol_id: pointer to UBI volume ID to be set ++ * ++ * Returns 0 on success and sets ubi_num and vol_id, returns error otherwise. ++ */ ++int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id) ++{ ++ int error; ++ struct path path; ++ struct kstat stat; ++ ++ error = kern_path(pathname, LOOKUP_FOLLOW, &path); ++ if (error) ++ return error; ++ ++ error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT); ++ path_put(&path); ++ if (error) ++ return error; ++ ++ if (!S_ISCHR(stat.mode)) ++ return -EINVAL; ++ ++ *ubi_num = ubi_major2num(MAJOR(stat.rdev)); ++ *vol_id = MINOR(stat.rdev) - 1; ++ ++ if (*vol_id < 0 || *ubi_num < 0) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++/** + * ubi_open_volume_path - open UBI volume by its character device node path. + * @pathname: volume character device node path + * @mode: open mode +@@ -290,32 +325,17 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm); + struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode) + { + int error, ubi_num, vol_id; +- struct path path; +- struct kstat stat; + + dbg_gen("open volume %s, mode %d", pathname, mode); + + if (!pathname || !*pathname) + return ERR_PTR(-EINVAL); + +- error = kern_path(pathname, LOOKUP_FOLLOW, &path); +- if (error) +- return ERR_PTR(error); +- +- error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT); +- path_put(&path); ++ error = ubi_get_num_by_path(pathname, &ubi_num, &vol_id); + if (error) + return ERR_PTR(error); + +- if (!S_ISCHR(stat.mode)) +- return ERR_PTR(-EINVAL); +- +- ubi_num = ubi_major2num(MAJOR(stat.rdev)); +- vol_id = MINOR(stat.rdev) - 1; +- +- if (vol_id >= 0 && ubi_num >= 0) +- return ubi_open_volume(ubi_num, vol_id, mode); +- return ERR_PTR(-ENODEV); ++ return ubi_open_volume(ubi_num, vol_id, mode); + } + EXPORT_SYMBOL_GPL(ubi_open_volume_path); + +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -956,6 +956,7 @@ void ubi_free_internal_volumes(struct ub + void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di); + void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol, + struct ubi_volume_info *vi); ++int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id); + /* scan.c */ + int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, + int pnum, const struct ubi_vid_hdr *vid_hdr); diff --git a/target/linux/generic/backport-6.6/404-v6.9-mtd-ubi-attach-from-device-tree.patch b/target/linux/generic/backport-6.6/404-v6.9-mtd-ubi-attach-from-device-tree.patch new file mode 100644 index 0000000000..ec7b6c3686 --- /dev/null +++ b/target/linux/generic/backport-6.6/404-v6.9-mtd-ubi-attach-from-device-tree.patch @@ -0,0 +1,205 @@ +From 6e331888643887ce85657527bc03f97d46235e71 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:33:14 +0000 +Subject: [PATCH 4/8] 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 +Signed-off-by: Richard Weinberger +--- + drivers/mtd/ubi/build.c | 135 ++++++++++++++++++++++++++++------------ + 1 file changed, 96 insertions(+), 39 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" +@@ -1214,43 +1215,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) ++{ ++ /* do nothing for now */ ++} + +- 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++) { +@@ -1298,25 +1299,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); ++ 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: +@@ -1326,13 +1381,15 @@ 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]) { diff --git a/target/linux/generic/backport-6.6/405-v6.9-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch b/target/linux/generic/backport-6.6/405-v6.9-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch new file mode 100644 index 0000000000..fb76ffc443 --- /dev/null +++ b/target/linux/generic/backport-6.6/405-v6.9-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch @@ -0,0 +1,180 @@ +From 924731fbed3247e3b82b8ab17db587ee28c2e781 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:33:24 +0000 +Subject: [PATCH 5/8] 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 +Signed-off-by: Richard Weinberger +--- + drivers/mtd/ubi/build.c | 19 ++++++++++++++----- + drivers/mtd/ubi/kapi.c | 2 +- + drivers/mtd/ubi/ubi.h | 2 ++ + drivers/mtd/ubi/vmt.c | 17 +++++++++++++++-- + include/linux/mtd/ubi.h | 2 ++ + 5 files changed, 34 insertions(+), 8 deletions(-) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -91,7 +91,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/' */ +@@ -259,6 +259,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; +@@ -296,7 +299,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); +@@ -325,7 +328,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; + } +@@ -512,7 +515,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,7 +1097,6 @@ 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) { +@@ -1105,6 +1107,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/backport-6.6/406-v6.9-mtd-ubi-populate-ubi-volume-fwnode.patch b/target/linux/generic/backport-6.6/406-v6.9-mtd-ubi-populate-ubi-volume-fwnode.patch new file mode 100644 index 0000000000..232e74da59 --- /dev/null +++ b/target/linux/generic/backport-6.6/406-v6.9-mtd-ubi-populate-ubi-volume-fwnode.patch @@ -0,0 +1,66 @@ +From 1c54542170819e36baa43c17ca55bb3d7da89a53 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:33:38 +0000 +Subject: [PATCH 6/8] 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 +Signed-off-by: Richard Weinberger +--- + 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/backport-6.6/407-v6.9-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch b/target/linux/generic/backport-6.6/407-v6.9-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch new file mode 100644 index 0000000000..18fd1fb437 --- /dev/null +++ b/target/linux/generic/backport-6.6/407-v6.9-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch @@ -0,0 +1,244 @@ +From 15fc7dc926c91c871f6c0305b2938dbdeb14203b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 19 Dec 2023 02:33:48 +0000 +Subject: [PATCH 7/8] 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 +Signed-off-by: Richard Weinberger +--- + 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/backport-6.6/408-v6.9-mtd-ubi-fix-NVMEM-over-UBI-volumes-on-32-bit-systems.patch b/target/linux/generic/backport-6.6/408-v6.9-mtd-ubi-fix-NVMEM-over-UBI-volumes-on-32-bit-systems.patch new file mode 100644 index 0000000000..8ce2b46691 --- /dev/null +++ b/target/linux/generic/backport-6.6/408-v6.9-mtd-ubi-fix-NVMEM-over-UBI-volumes-on-32-bit-systems.patch @@ -0,0 +1,34 @@ +From 04231c61dcd51db0f12061e49bb761b197109f2f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 29 Feb 2024 03:47:24 +0000 +Subject: [PATCH 8/8] mtd: ubi: fix NVMEM over UBI volumes on 32-bit systems + +A compiler warning related to sizeof(int) != 8 when calling do_div() +is triggered when building on 32-bit platforms. +Address this by using integer types having a well-defined size. + +Fixes: 3ce485803da1 ("mtd: ubi: provide NVMEM layer over UBI volumes") +Signed-off-by: Daniel Golle +Reviewed-by: Zhihao Cheng +Tested-by: Randy Dunlap +Signed-off-by: Richard Weinberger +--- + drivers/mtd/ubi/nvmem.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/ubi/nvmem.c ++++ b/drivers/mtd/ubi/nvmem.c +@@ -23,9 +23,12 @@ struct ubi_nvmem { + 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; ++ size_t to_read, bytes_left = bytes; + struct ubi_nvmem *unv = priv; + struct ubi_volume_desc *desc; ++ uint32_t offs; ++ uint64_t lnum = from; ++ int err = 0; + + desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY); + if (IS_ERR(desc)) diff --git a/target/linux/generic/pending-6.6/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch b/target/linux/generic/pending-6.6/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch deleted file mode 100644 index 063d3fa79c..0000000000 --- a/target/linux/generic/pending-6.6/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch +++ /dev/null @@ -1,121 +0,0 @@ -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.6/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch b/target/linux/generic/pending-6.6/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch deleted file mode 100644 index 823c8e83b7..0000000000 --- a/target/linux/generic/pending-6.6/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch +++ /dev/null @@ -1,48 +0,0 @@ -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.6/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch b/target/linux/generic/pending-6.6/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch deleted file mode 100644 index a1e1d6fa9d..0000000000 --- a/target/linux/generic/pending-6.6/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch +++ /dev/null @@ -1,225 +0,0 @@ -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 -@@ -65,10 +66,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; -@@ -469,7 +470,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; -@@ -532,6 +533,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) - { -@@ -539,10 +619,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); -@@ -568,56 +645,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; -@@ -643,18 +670,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.6/450-04-mtd-ubi-attach-from-device-tree.patch b/target/linux/generic/pending-6.6/450-04-mtd-ubi-attach-from-device-tree.patch deleted file mode 100644 index a295146aee..0000000000 --- a/target/linux/generic/pending-6.6/450-04-mtd-ubi-attach-from-device-tree.patch +++ /dev/null @@ -1,264 +0,0 @@ -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" -@@ -1072,6 +1073,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 -@@ -1081,7 +1083,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; - -@@ -1137,7 +1139,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; - } -@@ -1214,43 +1220,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++) { -@@ -1298,25 +1304,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: -@@ -1326,18 +1386,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.6/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch b/target/linux/generic/pending-6.6/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch deleted file mode 100644 index c7c058f8f4..0000000000 --- a/target/linux/generic/pending-6.6/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch +++ /dev/null @@ -1,226 +0,0 @@ -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 -@@ -533,6 +533,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) - { -@@ -624,6 +647,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 -@@ -91,7 +91,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/' */ -@@ -259,6 +259,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; -@@ -296,7 +299,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); -@@ -325,7 +328,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; - } -@@ -512,7 +515,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]); -@@ -1095,10 +1098,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; - } -@@ -1106,6 +1109,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.6/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch b/target/linux/generic/pending-6.6/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch deleted file mode 100644 index 1322766965..0000000000 --- a/target/linux/generic/pending-6.6/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch +++ /dev/null @@ -1,65 +0,0 @@ -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.6/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch b/target/linux/generic/pending-6.6/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch deleted file mode 100644 index 59a1eb9374..0000000000 --- a/target/linux/generic/pending-6.6/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch +++ /dev/null @@ -1,246 +0,0 @@ -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,191 @@ -+// 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) -+{ -+ uint32_t offs, to_read, bytes_left; -+ struct ubi_nvmem *unv = priv; -+ struct ubi_volume_desc *desc; -+ uint64_t lnum = from; -+ int err = 0; -+ -+ desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY); -+ if (IS_ERR(desc)) -+ return PTR_ERR(desc); -+ -+ bytes_left = bytes; -+ 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.6/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.6/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch index 5a897d5d6f..6405865c45 100644 --- a/target/linux/generic/pending-6.6/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch +++ b/target/linux/generic/pending-6.6/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c -@@ -1264,6 +1264,74 @@ static struct mtd_notifier ubi_mtd_notif +@@ -1258,6 +1258,74 @@ static struct mtd_notifier ubi_mtd_notif .remove = ubi_notify_remove, }; @@ -83,7 +83,7 @@ Signed-off-by: Daniel Golle static int __init ubi_init_attach(void) { int err, i, k; -@@ -1314,6 +1382,12 @@ static int __init ubi_init_attach(void) +@@ -1308,6 +1376,12 @@ static int __init ubi_init_attach(void) } } diff --git a/target/linux/generic/pending-6.6/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/pending-6.6/491-ubi-auto-create-ubiblock-device-for-rootfs.patch index e0134e876a..6081d1d9e5 100644 --- a/target/linux/generic/pending-6.6/491-ubi-auto-create-ubiblock-device-for-rootfs.patch +++ b/target/linux/generic/pending-6.6/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c -@@ -609,10 +609,47 @@ match_volume_desc(struct ubi_volume_info +@@ -570,10 +570,47 @@ match_volume_desc(struct ubi_volume_info return true; } @@ -56,7 +56,7 @@ Signed-off-by: Daniel Golle struct ubiblock_param *p; /* -@@ -625,6 +662,7 @@ ubiblock_create_from_param(struct ubi_vo +@@ -586,6 +623,7 @@ ubiblock_create_from_param(struct ubi_vo if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id)) continue; @@ -64,7 +64,7 @@ Signed-off-by: Daniel Golle ret = ubiblock_create(vi); if (ret) { pr_err( -@@ -633,6 +671,10 @@ ubiblock_create_from_param(struct ubi_vo +@@ -594,6 +632,10 @@ ubiblock_create_from_param(struct ubi_vo } break; } diff --git a/target/linux/generic/pending-6.6/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/pending-6.6/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch index 788690088a..367bf6598e 100644 --- a/target/linux/generic/pending-6.6/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch +++ b/target/linux/generic/pending-6.6/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 @@ +@@ -41,6 +41,7 @@ #include #include #include @@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle #include "ubi-media.h" #include "ubi.h" -@@ -429,6 +430,15 @@ int ubiblock_create(struct ubi_volume_in +@@ -428,6 +429,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/mediatek/patches-6.6/041-block-fit-partition-parser.patch b/target/linux/mediatek/patches-6.6/041-block-fit-partition-parser.patch index 2d85313f8d..185ec105d0 100644 --- a/target/linux/mediatek/patches-6.6/041-block-fit-partition-parser.patch +++ b/target/linux/mediatek/patches-6.6/041-block-fit-partition-parser.patch @@ -193,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 -@@ -411,7 +411,9 @@ int ubiblock_create(struct ubi_volume_in +@@ -410,7 +410,9 @@ int ubiblock_create(struct ubi_volume_in ret = -ENODEV; goto out_cleanup_disk; }