mirror of
https://github.com/openwrt/openwrt.git
synced 2025-02-01 08:48:08 +00:00
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 <daniel@makrotopia.org>
This commit is contained in:
parent
cff4335245
commit
fc153aa8d9
@ -266,7 +266,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
static inline int mmc_blk_part_switch(struct mmc_card *card,
|
||||
unsigned int part_type);
|
||||
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
@@ -3040,6 +3047,8 @@ static int mmc_blk_probe(struct mmc_card
|
||||
@@ -3049,6 +3056,8 @@ static int mmc_blk_probe(struct mmc_card
|
||||
{
|
||||
struct mmc_blk_data *md;
|
||||
int ret = 0;
|
||||
@ -275,7 +275,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
/*
|
||||
* Check that the card supports the command class(es) we need.
|
||||
@@ -3047,7 +3056,16 @@ static int mmc_blk_probe(struct mmc_card
|
||||
@@ -3056,7 +3065,16 @@ static int mmc_blk_probe(struct mmc_card
|
||||
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
|
||||
return -ENODEV;
|
||||
|
||||
@ -293,7 +293,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
card->complete_wq = alloc_workqueue("mmc_complete",
|
||||
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
|
||||
@@ -3062,6 +3080,17 @@ static int mmc_blk_probe(struct mmc_card
|
||||
@@ -3071,6 +3089,17 @@ static int mmc_blk_probe(struct mmc_card
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
|
@ -730,6 +730,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
|
||||
# CONFIG_BLK_DEV_VIA82CXXX is not set
|
||||
# CONFIG_BLK_DEV_ZONED is not set
|
||||
# CONFIG_BLK_INLINE_ENCRYPTION is not set
|
||||
# CONFIG_BLK_NVMEM is not set
|
||||
# CONFIG_BLK_SED_OPAL is not set
|
||||
# CONFIG_BLK_WBT is not set
|
||||
CONFIG_BLOCK=y
|
||||
@ -4037,6 +4038,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y
|
||||
# CONFIG_MTD_UBI is not set
|
||||
# CONFIG_MTD_UBI_FASTMAP is not set
|
||||
# CONFIG_MTD_UBI_GLUEBI is not set
|
||||
# CONFIG_MTD_UBI_NVMEM is not set
|
||||
# CONFIG_MTD_UIMAGE_SPLIT is not set
|
||||
# CONFIG_MTD_VIRT_CONCAT is not set
|
||||
# CONFIG_MTK_DEVAPC is not set
|
||||
|
@ -0,0 +1,121 @@
|
||||
From ffbbe7d66872ff8957dad2136133e28a1fd5d437 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 7 Aug 2023 22:51:05 +0100
|
||||
Subject: [PATCH 01/15] dt-bindings: mtd: add basic bindings for UBI
|
||||
|
||||
Add basic bindings for UBI devices and volumes.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
.../bindings/mtd/partitions/linux,ubi.yaml | 65 +++++++++++++++++++
|
||||
.../bindings/mtd/partitions/ubi-volume.yaml | 35 ++++++++++
|
||||
2 files changed, 100 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
|
||||
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
|
||||
@@ -0,0 +1,65 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Unsorted Block Images
|
||||
+
|
||||
+description: |
|
||||
+ UBI ("Unsorted Block Images") is a volume management system for raw
|
||||
+ flash devices which manages multiple logical volumes on a single
|
||||
+ physical flash device and spreads the I/O load (i.e wear-leveling)
|
||||
+ across the whole flash chip.
|
||||
+
|
||||
+maintainers:
|
||||
+ - Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+allOf:
|
||||
+ - $ref: partition.yaml#
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ const: linux,ubi
|
||||
+
|
||||
+ volumes:
|
||||
+ type: object
|
||||
+ description: UBI Volumes
|
||||
+
|
||||
+ patternProperties:
|
||||
+ "^ubi-volume-.*$":
|
||||
+ $ref: /schemas/mtd/partitions/ubi-volume.yaml#
|
||||
+
|
||||
+ unevaluatedProperties: false
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+
|
||||
+unevaluatedProperties: false
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ partitions {
|
||||
+ compatible = "fixed-partitions";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+
|
||||
+ partition@0 {
|
||||
+ reg = <0x0 0x100000>;
|
||||
+ label = "bootloader";
|
||||
+ read-only;
|
||||
+ };
|
||||
+
|
||||
+ partition@100000 {
|
||||
+ reg = <0x100000 0x1ff00000>;
|
||||
+ label = "ubi";
|
||||
+ compatible = "linux,ubi";
|
||||
+
|
||||
+ volumes {
|
||||
+ ubi-volume-caldata {
|
||||
+ volid = <2>;
|
||||
+ volname = "rf";
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
|
||||
@@ -0,0 +1,35 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: UBI volume
|
||||
+
|
||||
+description: |
|
||||
+ This binding describes a single UBI volume. Volumes can be matches either
|
||||
+ by their ID or their name, or both.
|
||||
+
|
||||
+maintainers:
|
||||
+ - Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+properties:
|
||||
+ volid:
|
||||
+ $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
+ description:
|
||||
+ Match UBI volume ID
|
||||
+
|
||||
+ volname:
|
||||
+ $ref: "/schemas/types.yaml#/definitions/string"
|
||||
+ description:
|
||||
+ Match UBI volume ID
|
||||
+
|
||||
+anyOf:
|
||||
+ - required:
|
||||
+ - volid
|
||||
+
|
||||
+ - required:
|
||||
+ - volname
|
||||
+
|
||||
+# This is a generic file other binding inherit from and extend
|
||||
+additionalProperties: true
|
@ -0,0 +1,48 @@
|
||||
From e4dad3aa5c3ab9c553555dd23c0b85f725f2eb51 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 7 Aug 2023 22:53:01 +0100
|
||||
Subject: [PATCH 02/15] dt-bindings: mtd: ubi-volume: allow UBI volumes to
|
||||
provide NVMEM
|
||||
|
||||
UBI volumes may be used to contain NVMEM bits, typically device MAC
|
||||
addresses or wireless radio calibration data.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
.../devicetree/bindings/mtd/partitions/linux,ubi.yaml | 10 ++++++++++
|
||||
.../devicetree/bindings/mtd/partitions/ubi-volume.yaml | 5 +++++
|
||||
2 files changed, 15 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
|
||||
+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
|
||||
@@ -59,6 +59,16 @@ examples:
|
||||
ubi-volume-caldata {
|
||||
volid = <2>;
|
||||
volname = "rf";
|
||||
+
|
||||
+ nvmem-layout {
|
||||
+ compatible = "fixed-layout";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+
|
||||
+ eeprom@0 {
|
||||
+ reg = <0x0 0x1000>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
};
|
||||
};
|
||||
--- a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
|
||||
+++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
|
||||
@@ -24,6 +24,11 @@ properties:
|
||||
description:
|
||||
Match UBI volume ID
|
||||
|
||||
+ nvmem-layout:
|
||||
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
|
||||
+ description:
|
||||
+ This container may reference an NVMEM layout parser.
|
||||
+
|
||||
anyOf:
|
||||
- required:
|
||||
- volid
|
@ -0,0 +1,225 @@
|
||||
From e5cf19bd8204925f3bd2067df9e867313eac388b Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 1 May 2023 11:57:51 +0100
|
||||
Subject: [PATCH 03/15] mtd: ubi: block: use notifier to create ubiblock from
|
||||
parameter
|
||||
|
||||
Use UBI_VOLUME_ADDED notification to create ubiblock device specified
|
||||
on kernel cmdline or module parameter.
|
||||
This makes thing more simple and has the advantage that ubiblock devices
|
||||
on volumes which are not present at the time the ubi module is probed
|
||||
will still be created.
|
||||
|
||||
Suggested-by: Zhihao Cheng <chengzhihao1@huawei.com>
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/block.c | 154 ++++++++++++++++++++++------------------
|
||||
1 file changed, 85 insertions(+), 69 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mtd/ubi.h>
|
||||
#include <linux/workqueue.h>
|
||||
@@ -67,10 +68,10 @@ struct ubiblock_pdu {
|
||||
};
|
||||
|
||||
/* Numbers of elements set in the @ubiblock_param array */
|
||||
-static int ubiblock_devs __initdata;
|
||||
+static int ubiblock_devs;
|
||||
|
||||
/* MTD devices specification parameters */
|
||||
-static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
|
||||
+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
|
||||
|
||||
struct ubiblock {
|
||||
struct ubi_volume_desc *desc;
|
||||
@@ -504,7 +505,7 @@ int ubiblock_remove(struct ubi_volume_in
|
||||
}
|
||||
|
||||
/* Found a device, let's lock it so we can check if it's busy */
|
||||
- mutex_lock(&dev->dev_mutex);
|
||||
+ mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
|
||||
if (dev->refcnt > 0) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock_dev;
|
||||
@@ -567,6 +568,85 @@ static int ubiblock_resize(struct ubi_vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static bool
|
||||
+match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
|
||||
+{
|
||||
+ int err, len;
|
||||
+ struct path path;
|
||||
+ struct kstat stat;
|
||||
+
|
||||
+ if (ubi_num == -1) {
|
||||
+ /* No ubi num, name must be a vol device path */
|
||||
+ err = kern_path(name, LOOKUP_FOLLOW, &path);
|
||||
+ if (err)
|
||||
+ return false;
|
||||
+
|
||||
+ err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
|
||||
+ path_put(&path);
|
||||
+ if (err)
|
||||
+ return false;
|
||||
+
|
||||
+ if (!S_ISCHR(stat.mode))
|
||||
+ return false;
|
||||
+
|
||||
+ if (vi->ubi_num != ubi_major2num(MAJOR(stat.rdev)))
|
||||
+ return false;
|
||||
+
|
||||
+ if (vi->vol_id != MINOR(stat.rdev) - 1)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ if (vol_id == -1) {
|
||||
+ if (vi->ubi_num != ubi_num)
|
||||
+ return false;
|
||||
+
|
||||
+ len = strnlen(name, UBI_VOL_NAME_MAX + 1);
|
||||
+ if (len < 1 || vi->name_len != len)
|
||||
+ return false;
|
||||
+
|
||||
+ if (strcmp(name, vi->name))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ if (vi->ubi_num != ubi_num)
|
||||
+ return false;
|
||||
+
|
||||
+ if (vi->vol_id != vol_id)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+ubiblock_create_from_param(struct ubi_volume_info *vi)
|
||||
+{
|
||||
+ int i, ret = 0;
|
||||
+ struct ubiblock_param *p;
|
||||
+
|
||||
+ /*
|
||||
+ * Iterate over ubiblock cmdline parameters. If a parameter matches the
|
||||
+ * newly added volume create the ubiblock device for it.
|
||||
+ */
|
||||
+ for (i = 0; i < ubiblock_devs; i++) {
|
||||
+ p = &ubiblock_param[i];
|
||||
+
|
||||
+ if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
|
||||
+ continue;
|
||||
+
|
||||
+ ret = ubiblock_create(vi);
|
||||
+ if (ret) {
|
||||
+ pr_err(
|
||||
+ "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
|
||||
+ vi->name, p->ubi_num, p->vol_id, ret);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int ubiblock_notify(struct notifier_block *nb,
|
||||
unsigned long notification_type, void *ns_ptr)
|
||||
{
|
||||
@@ -574,10 +654,7 @@ static int ubiblock_notify(struct notifi
|
||||
|
||||
switch (notification_type) {
|
||||
case UBI_VOLUME_ADDED:
|
||||
- /*
|
||||
- * We want to enforce explicit block device creation for
|
||||
- * volumes, so when a volume is added we do nothing.
|
||||
- */
|
||||
+ ubiblock_create_from_param(&nt->vi);
|
||||
break;
|
||||
case UBI_VOLUME_REMOVED:
|
||||
ubiblock_remove(&nt->vi);
|
||||
@@ -603,56 +680,6 @@ static struct notifier_block ubiblock_no
|
||||
.notifier_call = ubiblock_notify,
|
||||
};
|
||||
|
||||
-static struct ubi_volume_desc * __init
|
||||
-open_volume_desc(const char *name, int ubi_num, int vol_id)
|
||||
-{
|
||||
- if (ubi_num == -1)
|
||||
- /* No ubi num, name must be a vol device path */
|
||||
- return ubi_open_volume_path(name, UBI_READONLY);
|
||||
- else if (vol_id == -1)
|
||||
- /* No vol_id, must be vol_name */
|
||||
- return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
|
||||
- else
|
||||
- return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
|
||||
-}
|
||||
-
|
||||
-static void __init ubiblock_create_from_param(void)
|
||||
-{
|
||||
- int i, ret = 0;
|
||||
- struct ubiblock_param *p;
|
||||
- struct ubi_volume_desc *desc;
|
||||
- struct ubi_volume_info vi;
|
||||
-
|
||||
- /*
|
||||
- * If there is an error creating one of the ubiblocks, continue on to
|
||||
- * create the following ubiblocks. This helps in a circumstance where
|
||||
- * the kernel command-line specifies multiple block devices and some
|
||||
- * may be broken, but we still want the working ones to come up.
|
||||
- */
|
||||
- for (i = 0; i < ubiblock_devs; i++) {
|
||||
- p = &ubiblock_param[i];
|
||||
-
|
||||
- desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
|
||||
- if (IS_ERR(desc)) {
|
||||
- pr_err(
|
||||
- "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
|
||||
- p->ubi_num, p->vol_id, PTR_ERR(desc));
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- ubi_get_volume_info(desc, &vi);
|
||||
- ubi_close_volume(desc);
|
||||
-
|
||||
- ret = ubiblock_create(&vi);
|
||||
- if (ret) {
|
||||
- pr_err(
|
||||
- "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
|
||||
- vi.name, p->ubi_num, p->vol_id, ret);
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static void ubiblock_remove_all(void)
|
||||
{
|
||||
struct ubiblock *next;
|
||||
@@ -678,18 +705,7 @@ int __init ubiblock_init(void)
|
||||
if (ubiblock_major < 0)
|
||||
return ubiblock_major;
|
||||
|
||||
- /*
|
||||
- * Attach block devices from 'block=' module param.
|
||||
- * Even if one block device in the param list fails to come up,
|
||||
- * still allow the module to load and leave any others up.
|
||||
- */
|
||||
- ubiblock_create_from_param();
|
||||
-
|
||||
- /*
|
||||
- * Block devices are only created upon user requests, so we ignore
|
||||
- * existing volumes.
|
||||
- */
|
||||
- ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
|
||||
+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
|
||||
if (ret)
|
||||
goto err_unreg;
|
||||
return 0;
|
@ -0,0 +1,264 @@
|
||||
From 471a17d8d1b838092d1a76e48cdce8b5b67ff809 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 27 Nov 2023 01:54:28 +0000
|
||||
Subject: [PATCH 04/15] mtd: ubi: attach from device tree
|
||||
|
||||
Introduce device tree compatible 'linux,ubi' and attach compatible MTD
|
||||
devices using the MTD add notifier. This is needed for a UBI device to
|
||||
be available early at boot (and not only after late_initcall), so
|
||||
volumes on them can be used eg. as NVMEM providers for other drivers.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/build.c | 146 ++++++++++++++++++++++++++++------------
|
||||
drivers/mtd/ubi/cdev.c | 2 +-
|
||||
drivers/mtd/ubi/ubi.h | 2 +-
|
||||
3 files changed, 106 insertions(+), 44 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/ubi/build.c
|
||||
+++ b/drivers/mtd/ubi/build.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/major.h>
|
||||
#include "ubi.h"
|
||||
@@ -1071,6 +1072,7 @@ out_free:
|
||||
* ubi_detach_mtd_dev - detach an MTD device.
|
||||
* @ubi_num: UBI device number to detach from
|
||||
* @anyway: detach MTD even if device reference count is not zero
|
||||
+ * @have_lock: called by MTD notifier holding mtd_table_mutex
|
||||
*
|
||||
* This function destroys an UBI device number @ubi_num and detaches the
|
||||
* underlying MTD device. Returns zero in case of success and %-EBUSY if the
|
||||
@@ -1080,7 +1082,7 @@ out_free:
|
||||
* Note, the invocations of this function has to be serialized by the
|
||||
* @ubi_devices_mutex.
|
||||
*/
|
||||
-int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
||||
+int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
|
||||
{
|
||||
struct ubi_device *ubi;
|
||||
|
||||
@@ -1136,7 +1138,11 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
||||
vfree(ubi->peb_buf);
|
||||
vfree(ubi->fm_buf);
|
||||
ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
|
||||
- put_mtd_device(ubi->mtd);
|
||||
+ if (have_lock)
|
||||
+ __put_mtd_device(ubi->mtd);
|
||||
+ else
|
||||
+ put_mtd_device(ubi->mtd);
|
||||
+
|
||||
put_device(&ubi->dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -1213,43 +1219,43 @@ static struct mtd_info * __init open_mtd
|
||||
return mtd;
|
||||
}
|
||||
|
||||
-static int __init ubi_init(void)
|
||||
+static void ubi_notify_add(struct mtd_info *mtd)
|
||||
{
|
||||
- int err, i, k;
|
||||
+ struct device_node *np = mtd_get_of_node(mtd);
|
||||
+ int err;
|
||||
|
||||
- /* Ensure that EC and VID headers have correct size */
|
||||
- BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
|
||||
- BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
|
||||
+ if (!of_device_is_compatible(np, "linux,ubi"))
|
||||
+ return;
|
||||
|
||||
- if (mtd_devs > UBI_MAX_DEVICES) {
|
||||
- pr_err("UBI error: too many MTD devices, maximum is %d\n",
|
||||
- UBI_MAX_DEVICES);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ /*
|
||||
+ * we are already holding &mtd_table_mutex, but still need
|
||||
+ * to bump refcount
|
||||
+ */
|
||||
+ err = __get_mtd_device(mtd);
|
||||
+ if (err)
|
||||
+ return;
|
||||
|
||||
- /* Create base sysfs directory and sysfs files */
|
||||
- err = class_register(&ubi_class);
|
||||
+ /* called while holding mtd_table_mutex */
|
||||
+ mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
|
||||
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
|
||||
+ mutex_unlock(&ubi_devices_mutex);
|
||||
if (err < 0)
|
||||
- return err;
|
||||
-
|
||||
- err = misc_register(&ubi_ctrl_cdev);
|
||||
- if (err) {
|
||||
- pr_err("UBI error: cannot register device\n");
|
||||
- goto out;
|
||||
- }
|
||||
+ __put_mtd_device(mtd);
|
||||
+}
|
||||
|
||||
- ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
|
||||
- sizeof(struct ubi_wl_entry),
|
||||
- 0, 0, NULL);
|
||||
- if (!ubi_wl_entry_slab) {
|
||||
- err = -ENOMEM;
|
||||
- goto out_dev_unreg;
|
||||
- }
|
||||
+static void ubi_notify_remove(struct mtd_info *mtd)
|
||||
+{
|
||||
+ WARN(1, "mtd%d removed despite UBI still being attached", mtd->index);
|
||||
+}
|
||||
|
||||
- err = ubi_debugfs_init();
|
||||
- if (err)
|
||||
- goto out_slab;
|
||||
+static struct mtd_notifier ubi_mtd_notifier = {
|
||||
+ .add = ubi_notify_add,
|
||||
+ .remove = ubi_notify_remove,
|
||||
+};
|
||||
|
||||
+static int __init ubi_init_attach(void)
|
||||
+{
|
||||
+ int err, i, k;
|
||||
|
||||
/* Attach MTD devices */
|
||||
for (i = 0; i < mtd_devs; i++) {
|
||||
@@ -1297,25 +1303,79 @@ static int __init ubi_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
+ return 0;
|
||||
+
|
||||
+out_detach:
|
||||
+ for (k = 0; k < i; k++)
|
||||
+ if (ubi_devices[k]) {
|
||||
+ mutex_lock(&ubi_devices_mutex);
|
||||
+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1, false);
|
||||
+ mutex_unlock(&ubi_devices_mutex);
|
||||
+ }
|
||||
+ return err;
|
||||
+}
|
||||
+#ifndef CONFIG_MTD_UBI_MODULE
|
||||
+late_initcall(ubi_init_attach);
|
||||
+#endif
|
||||
+
|
||||
+static int __init ubi_init(void)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* Ensure that EC and VID headers have correct size */
|
||||
+ BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
|
||||
+ BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
|
||||
+
|
||||
+ if (mtd_devs > UBI_MAX_DEVICES) {
|
||||
+ pr_err("UBI error: too many MTD devices, maximum is %d\n",
|
||||
+ UBI_MAX_DEVICES);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* Create base sysfs directory and sysfs files */
|
||||
+ err = class_register(&ubi_class);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ err = misc_register(&ubi_ctrl_cdev);
|
||||
+ if (err) {
|
||||
+ pr_err("UBI error: cannot register device\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
|
||||
+ sizeof(struct ubi_wl_entry),
|
||||
+ 0, 0, NULL);
|
||||
+ if (!ubi_wl_entry_slab) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto out_dev_unreg;
|
||||
+ }
|
||||
+
|
||||
+ err = ubi_debugfs_init();
|
||||
+ if (err)
|
||||
+ goto out_slab;
|
||||
+
|
||||
err = ubiblock_init();
|
||||
if (err) {
|
||||
pr_err("UBI error: block: cannot initialize, error %d\n", err);
|
||||
|
||||
/* See comment above re-ubi_is_module(). */
|
||||
if (ubi_is_module())
|
||||
- goto out_detach;
|
||||
+ goto out_slab;
|
||||
+ }
|
||||
+
|
||||
+ register_mtd_user(&ubi_mtd_notifier);
|
||||
+
|
||||
+ if (ubi_is_module()) {
|
||||
+ err = ubi_init_attach();
|
||||
+ if (err)
|
||||
+ goto out_mtd_notifier;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
-out_detach:
|
||||
- for (k = 0; k < i; k++)
|
||||
- if (ubi_devices[k]) {
|
||||
- mutex_lock(&ubi_devices_mutex);
|
||||
- ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
|
||||
- mutex_unlock(&ubi_devices_mutex);
|
||||
- }
|
||||
- ubi_debugfs_exit();
|
||||
+out_mtd_notifier:
|
||||
+ unregister_mtd_user(&ubi_mtd_notifier);
|
||||
out_slab:
|
||||
kmem_cache_destroy(ubi_wl_entry_slab);
|
||||
out_dev_unreg:
|
||||
@@ -1325,18 +1385,20 @@ out:
|
||||
pr_err("UBI error: cannot initialize UBI, error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
-late_initcall(ubi_init);
|
||||
+device_initcall(ubi_init);
|
||||
+
|
||||
|
||||
static void __exit ubi_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ubiblock_exit();
|
||||
+ unregister_mtd_user(&ubi_mtd_notifier);
|
||||
|
||||
for (i = 0; i < UBI_MAX_DEVICES; i++)
|
||||
if (ubi_devices[i]) {
|
||||
mutex_lock(&ubi_devices_mutex);
|
||||
- ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
|
||||
+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, false);
|
||||
mutex_unlock(&ubi_devices_mutex);
|
||||
}
|
||||
ubi_debugfs_exit();
|
||||
--- a/drivers/mtd/ubi/cdev.c
|
||||
+++ b/drivers/mtd/ubi/cdev.c
|
||||
@@ -1065,7 +1065,7 @@ static long ctrl_cdev_ioctl(struct file
|
||||
}
|
||||
|
||||
mutex_lock(&ubi_devices_mutex);
|
||||
- err = ubi_detach_mtd_dev(ubi_num, 0);
|
||||
+ err = ubi_detach_mtd_dev(ubi_num, 0, false);
|
||||
mutex_unlock(&ubi_devices_mutex);
|
||||
break;
|
||||
}
|
||||
--- a/drivers/mtd/ubi/ubi.h
|
||||
+++ b/drivers/mtd/ubi/ubi.h
|
||||
@@ -939,7 +939,7 @@ int ubi_io_write_vid_hdr(struct ubi_devi
|
||||
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
|
||||
int vid_hdr_offset, int max_beb_per1024,
|
||||
bool disable_fm);
|
||||
-int ubi_detach_mtd_dev(int ubi_num, int anyway);
|
||||
+int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock);
|
||||
struct ubi_device *ubi_get_device(int ubi_num);
|
||||
void ubi_put_device(struct ubi_device *ubi);
|
||||
struct ubi_device *ubi_get_by_major(int major);
|
@ -0,0 +1,226 @@
|
||||
From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 8 Jun 2023 17:18:09 +0100
|
||||
Subject: [PATCH 05/15] mtd: ubi: introduce pre-removal notification for UBI
|
||||
volumes
|
||||
|
||||
Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
|
||||
that a volume is just about to be removed.
|
||||
This is needed because users (such as the NVMEM subsystem) expect that
|
||||
at the time their removal function is called, the parenting device is
|
||||
still available (for removal of sysfs nodes, for example, in case of
|
||||
NVMEM which otherwise WARNs on volume removal).
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
|
||||
drivers/mtd/ubi/build.c | 20 +++++++++++++++-----
|
||||
drivers/mtd/ubi/kapi.c | 2 +-
|
||||
drivers/mtd/ubi/ubi.h | 2 ++
|
||||
drivers/mtd/ubi/vmt.c | 17 +++++++++++++++--
|
||||
include/linux/mtd/ubi.h | 2 ++
|
||||
6 files changed, 61 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -568,6 +568,29 @@ static int ubiblock_resize(struct ubi_vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int ubiblock_shutdown(struct ubi_volume_info *vi)
|
||||
+{
|
||||
+ struct ubiblock *dev;
|
||||
+ struct gendisk *disk;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
|
||||
+ if (!dev) {
|
||||
+ ret = -ENODEV;
|
||||
+ goto out_unlock;
|
||||
+ }
|
||||
+ disk = dev->gd;
|
||||
+
|
||||
+out_unlock:
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+
|
||||
+ if (!ret)
|
||||
+ blk_mark_disk_dead(disk);
|
||||
+
|
||||
+ return ret;
|
||||
+};
|
||||
+
|
||||
static bool
|
||||
match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
|
||||
{
|
||||
@@ -659,6 +682,9 @@ static int ubiblock_notify(struct notifi
|
||||
case UBI_VOLUME_REMOVED:
|
||||
ubiblock_remove(&nt->vi);
|
||||
break;
|
||||
+ case UBI_VOLUME_SHUTDOWN:
|
||||
+ ubiblock_shutdown(&nt->vi);
|
||||
+ break;
|
||||
case UBI_VOLUME_RESIZED:
|
||||
ubiblock_resize(&nt->vi);
|
||||
break;
|
||||
--- a/drivers/mtd/ubi/build.c
|
||||
+++ b/drivers/mtd/ubi/build.c
|
||||
@@ -89,7 +89,7 @@ static struct ubi_device *ubi_devices[UB
|
||||
/* Serializes UBI devices creations and removals */
|
||||
DEFINE_MUTEX(ubi_devices_mutex);
|
||||
|
||||
-/* Protects @ubi_devices and @ubi->ref_count */
|
||||
+/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
|
||||
static DEFINE_SPINLOCK(ubi_devices_lock);
|
||||
|
||||
/* "Show" method for files in '/<sysfs>/class/ubi/' */
|
||||
@@ -258,6 +258,9 @@ struct ubi_device *ubi_get_device(int ub
|
||||
|
||||
spin_lock(&ubi_devices_lock);
|
||||
ubi = ubi_devices[ubi_num];
|
||||
+ if (ubi && ubi->is_dead)
|
||||
+ ubi = NULL;
|
||||
+
|
||||
if (ubi) {
|
||||
ubi_assert(ubi->ref_count >= 0);
|
||||
ubi->ref_count += 1;
|
||||
@@ -295,7 +298,7 @@ struct ubi_device *ubi_get_by_major(int
|
||||
spin_lock(&ubi_devices_lock);
|
||||
for (i = 0; i < UBI_MAX_DEVICES; i++) {
|
||||
ubi = ubi_devices[i];
|
||||
- if (ubi && MAJOR(ubi->cdev.dev) == major) {
|
||||
+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
|
||||
ubi_assert(ubi->ref_count >= 0);
|
||||
ubi->ref_count += 1;
|
||||
get_device(&ubi->dev);
|
||||
@@ -324,7 +327,7 @@ int ubi_major2num(int major)
|
||||
for (i = 0; i < UBI_MAX_DEVICES; i++) {
|
||||
struct ubi_device *ubi = ubi_devices[i];
|
||||
|
||||
- if (ubi && MAJOR(ubi->cdev.dev) == major) {
|
||||
+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
|
||||
ubi_num = ubi->ubi_num;
|
||||
break;
|
||||
}
|
||||
@@ -511,7 +514,7 @@ static void ubi_free_volumes_from(struct
|
||||
int i;
|
||||
|
||||
for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
|
||||
- if (!ubi->volumes[i])
|
||||
+ if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
|
||||
continue;
|
||||
ubi_eba_replace_table(ubi->volumes[i], NULL);
|
||||
ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
|
||||
@@ -1094,10 +1097,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&ubi_devices_lock);
|
||||
- put_device(&ubi->dev);
|
||||
ubi->ref_count -= 1;
|
||||
if (ubi->ref_count) {
|
||||
if (!anyway) {
|
||||
+ ubi->ref_count += 1;
|
||||
spin_unlock(&ubi_devices_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
@@ -1105,6 +1108,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
||||
ubi_err(ubi, "%s reference count %d, destroy anyway",
|
||||
ubi->ubi_name, ubi->ref_count);
|
||||
}
|
||||
+ ubi->is_dead = true;
|
||||
+ spin_unlock(&ubi_devices_lock);
|
||||
+
|
||||
+ ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
|
||||
+
|
||||
+ spin_lock(&ubi_devices_lock);
|
||||
+ put_device(&ubi->dev);
|
||||
ubi_devices[ubi_num] = NULL;
|
||||
spin_unlock(&ubi_devices_lock);
|
||||
|
||||
--- a/drivers/mtd/ubi/kapi.c
|
||||
+++ b/drivers/mtd/ubi/kapi.c
|
||||
@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
|
||||
|
||||
spin_lock(&ubi->volumes_lock);
|
||||
vol = ubi->volumes[vol_id];
|
||||
- if (!vol)
|
||||
+ if (!vol || vol->is_dead)
|
||||
goto out_unlock;
|
||||
|
||||
err = -EBUSY;
|
||||
--- a/drivers/mtd/ubi/ubi.h
|
||||
+++ b/drivers/mtd/ubi/ubi.h
|
||||
@@ -345,6 +345,7 @@ struct ubi_volume {
|
||||
int writers;
|
||||
int exclusive;
|
||||
int metaonly;
|
||||
+ bool is_dead;
|
||||
|
||||
int reserved_pebs;
|
||||
int vol_type;
|
||||
@@ -564,6 +565,7 @@ struct ubi_device {
|
||||
spinlock_t volumes_lock;
|
||||
int ref_count;
|
||||
int image_seq;
|
||||
+ bool is_dead;
|
||||
|
||||
int rsvd_pebs;
|
||||
int avail_pebs;
|
||||
--- a/drivers/mtd/ubi/vmt.c
|
||||
+++ b/drivers/mtd/ubi/vmt.c
|
||||
@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
|
||||
struct ubi_device *ubi = vol->ubi;
|
||||
|
||||
spin_lock(&ubi->volumes_lock);
|
||||
- if (!ubi->volumes[vol->vol_id]) {
|
||||
+ if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
|
||||
|
||||
/* Ensure that the name is unique */
|
||||
for (i = 0; i < ubi->vtbl_slots; i++)
|
||||
- if (ubi->volumes[i] &&
|
||||
+ if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
|
||||
ubi->volumes[i]->name_len == req->name_len &&
|
||||
!strcmp(ubi->volumes[i]->name, req->name)) {
|
||||
ubi_err(ubi, "volume \"%s\" exists (ID %d)",
|
||||
@@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
|
||||
err = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
+
|
||||
+ /*
|
||||
+ * Mark volume as dead at this point to prevent that anyone
|
||||
+ * can take a reference to the volume from now on.
|
||||
+ * This is necessary as we have to release the spinlock before
|
||||
+ * calling ubi_volume_notify.
|
||||
+ */
|
||||
+ vol->is_dead = true;
|
||||
+ spin_unlock(&ubi->volumes_lock);
|
||||
+
|
||||
+ ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
|
||||
+
|
||||
+ spin_lock(&ubi->volumes_lock);
|
||||
ubi->volumes[vol_id] = NULL;
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
|
||||
--- a/include/linux/mtd/ubi.h
|
||||
+++ b/include/linux/mtd/ubi.h
|
||||
@@ -192,6 +192,7 @@ struct ubi_device_info {
|
||||
* or a volume was removed)
|
||||
* @UBI_VOLUME_RESIZED: a volume has been re-sized
|
||||
* @UBI_VOLUME_RENAMED: a volume has been re-named
|
||||
+ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
|
||||
* @UBI_VOLUME_UPDATED: data has been written to a volume
|
||||
*
|
||||
* These constants define which type of event has happened when a volume
|
||||
@@ -202,6 +203,7 @@ enum {
|
||||
UBI_VOLUME_REMOVED,
|
||||
UBI_VOLUME_RESIZED,
|
||||
UBI_VOLUME_RENAMED,
|
||||
+ UBI_VOLUME_SHUTDOWN,
|
||||
UBI_VOLUME_UPDATED,
|
||||
};
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 3a041ee543cdf2e707a1dd72946cd6a583509b28 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Fri, 21 Jul 2023 19:26:37 +0100
|
||||
Subject: [PATCH 06/15] mtd: ubi: populate ubi volume fwnode
|
||||
|
||||
Look for the 'volumes' subnode of an MTD partition attached to a UBI
|
||||
device and attach matching child nodes to UBI volumes.
|
||||
This allows UBI volumes to be referenced in device tree, e.g. for use
|
||||
as NVMEM providers.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/vmt.c | 27 +++++++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/ubi/vmt.c
|
||||
+++ b/drivers/mtd/ubi/vmt.c
|
||||
@@ -124,6 +124,31 @@ static void vol_release(struct device *d
|
||||
kfree(vol);
|
||||
}
|
||||
|
||||
+static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
|
||||
+{
|
||||
+ struct fwnode_handle *fw_vols, *fw_vol;
|
||||
+ const char *volname;
|
||||
+ u32 volid;
|
||||
+
|
||||
+ fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
|
||||
+ if (!fw_vols)
|
||||
+ return NULL;
|
||||
+
|
||||
+ fwnode_for_each_child_node(fw_vols, fw_vol) {
|
||||
+ if (!fwnode_property_read_string(fw_vol, "volname", &volname) &&
|
||||
+ strncmp(volname, vol->name, vol->name_len))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!fwnode_property_read_u32(fw_vol, "volid", &volid) &&
|
||||
+ vol->vol_id != volid)
|
||||
+ continue;
|
||||
+
|
||||
+ return fw_vol;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* ubi_create_volume - create volume.
|
||||
* @ubi: UBI device description object
|
||||
@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device
|
||||
vol->name_len = req->name_len;
|
||||
memcpy(vol->name, req->name, vol->name_len);
|
||||
vol->ubi = ubi;
|
||||
+ device_set_node(&vol->dev, find_volume_fwnode(vol));
|
||||
|
||||
/*
|
||||
* Finish all pending erases because there may be some LEBs belonging
|
||||
@@ -605,6 +631,7 @@ int ubi_add_volume(struct ubi_device *ub
|
||||
vol->dev.class = &ubi_class;
|
||||
vol->dev.groups = volume_dev_groups;
|
||||
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
|
||||
+ device_set_node(&vol->dev, find_volume_fwnode(vol));
|
||||
err = device_register(&vol->dev);
|
||||
if (err) {
|
||||
cdev_del(&vol->cdev);
|
@ -0,0 +1,243 @@
|
||||
From 7eb6666348f3f2d1f7308c712fa5903cbe189401 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 8 Jun 2023 17:22:04 +0100
|
||||
Subject: [PATCH 07/15] mtd: ubi: provide NVMEM layer over UBI volumes
|
||||
|
||||
In an ideal world we would like UBI to be used where ever possible on a
|
||||
NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
|
||||
is possible to achieve an (almost-)all-UBI flash layout. Hence the need
|
||||
for a way to also use UBI volumes to store board-level constants, such
|
||||
as MAC addresses and calibration data of wireless interfaces.
|
||||
|
||||
Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
|
||||
providers. Allow UBI devices to have a "volumes" firmware subnode with
|
||||
volumes which may be compatible with "nvmem-cells".
|
||||
Access to UBI volumes via the NVMEM interface at this point is
|
||||
read-only, and it is slow, opening and closing the UBI volume for each
|
||||
access due to limitations of the NVMEM provider API.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/Kconfig | 12 +++
|
||||
drivers/mtd/ubi/Makefile | 1 +
|
||||
drivers/mtd/ubi/nvmem.c | 188 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 201 insertions(+)
|
||||
create mode 100644 drivers/mtd/ubi/nvmem.c
|
||||
|
||||
--- a/drivers/mtd/ubi/Kconfig
|
||||
+++ b/drivers/mtd/ubi/Kconfig
|
||||
@@ -104,4 +104,16 @@ config MTD_UBI_BLOCK
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
+config MTD_UBI_NVMEM
|
||||
+ tristate "UBI virtual NVMEM"
|
||||
+ default n
|
||||
+ depends on NVMEM
|
||||
+ help
|
||||
+ This option enabled an additional driver exposing UBI volumes as NVMEM
|
||||
+ providers, intended for platforms where UBI is part of the firmware
|
||||
+ specification and used to store also e.g. MAC addresses or board-
|
||||
+ specific Wi-Fi calibration data.
|
||||
+
|
||||
+ If in doubt, say "N".
|
||||
+
|
||||
endif # MTD_UBI
|
||||
--- a/drivers/mtd/ubi/Makefile
|
||||
+++ b/drivers/mtd/ubi/Makefile
|
||||
@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap
|
||||
ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
|
||||
|
||||
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
|
||||
+obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/ubi/nvmem.c
|
||||
@@ -0,0 +1,188 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
|
||||
+ */
|
||||
+
|
||||
+/* UBI NVMEM provider */
|
||||
+#include "ubi.h"
|
||||
+#include <linux/nvmem-provider.h>
|
||||
+#include <asm/div64.h>
|
||||
+
|
||||
+/* List of all NVMEM devices */
|
||||
+static LIST_HEAD(nvmem_devices);
|
||||
+static DEFINE_MUTEX(devices_mutex);
|
||||
+
|
||||
+struct ubi_nvmem {
|
||||
+ struct nvmem_device *nvmem;
|
||||
+ int ubi_num;
|
||||
+ int vol_id;
|
||||
+ int usable_leb_size;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+static int ubi_nvmem_reg_read(void *priv, unsigned int from,
|
||||
+ void *val, size_t bytes)
|
||||
+{
|
||||
+ int err = 0, lnum = from, offs, bytes_left = bytes, to_read;
|
||||
+ struct ubi_nvmem *unv = priv;
|
||||
+ struct ubi_volume_desc *desc;
|
||||
+
|
||||
+ desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
|
||||
+ if (IS_ERR(desc))
|
||||
+ return PTR_ERR(desc);
|
||||
+
|
||||
+ offs = do_div(lnum, unv->usable_leb_size);
|
||||
+ while (bytes_left) {
|
||||
+ to_read = unv->usable_leb_size - offs;
|
||||
+
|
||||
+ if (to_read > bytes_left)
|
||||
+ to_read = bytes_left;
|
||||
+
|
||||
+ err = ubi_read(desc, lnum, val, offs, to_read);
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ lnum += 1;
|
||||
+ offs = 0;
|
||||
+ bytes_left -= to_read;
|
||||
+ val += to_read;
|
||||
+ }
|
||||
+ ubi_close_volume(desc);
|
||||
+
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ return bytes_left == 0 ? 0 : -EIO;
|
||||
+}
|
||||
+
|
||||
+static int ubi_nvmem_add(struct ubi_volume_info *vi)
|
||||
+{
|
||||
+ struct device_node *np = dev_of_node(vi->dev);
|
||||
+ struct nvmem_config config = {};
|
||||
+ struct ubi_nvmem *unv;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!of_get_child_by_name(np, "nvmem-layout"))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (WARN_ON_ONCE(vi->usable_leb_size <= 0) ||
|
||||
+ WARN_ON_ONCE(vi->size <= 0))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
|
||||
+ if (!unv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ config.id = NVMEM_DEVID_NONE;
|
||||
+ config.dev = vi->dev;
|
||||
+ config.name = dev_name(vi->dev);
|
||||
+ config.owner = THIS_MODULE;
|
||||
+ config.priv = unv;
|
||||
+ config.reg_read = ubi_nvmem_reg_read;
|
||||
+ config.size = vi->usable_leb_size * vi->size;
|
||||
+ config.word_size = 1;
|
||||
+ config.stride = 1;
|
||||
+ config.read_only = true;
|
||||
+ config.root_only = true;
|
||||
+ config.ignore_wp = true;
|
||||
+ config.of_node = np;
|
||||
+
|
||||
+ unv->ubi_num = vi->ubi_num;
|
||||
+ unv->vol_id = vi->vol_id;
|
||||
+ unv->usable_leb_size = vi->usable_leb_size;
|
||||
+ unv->nvmem = nvmem_register(&config);
|
||||
+ if (IS_ERR(unv->nvmem)) {
|
||||
+ ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
|
||||
+ "Failed to register NVMEM device\n");
|
||||
+ kfree(unv);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ list_add_tail(&unv->list, &nvmem_devices);
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ubi_nvmem_remove(struct ubi_volume_info *vi)
|
||||
+{
|
||||
+ struct ubi_nvmem *unv_c, *unv = NULL;
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ list_for_each_entry(unv_c, &nvmem_devices, list)
|
||||
+ if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
|
||||
+ unv = unv_c;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!unv) {
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ list_del(&unv->list);
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+ nvmem_unregister(unv->nvmem);
|
||||
+ kfree(unv);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * nvmem_notify - UBI notification handler.
|
||||
+ * @nb: registered notifier block
|
||||
+ * @l: notification type
|
||||
+ * @ns_ptr: pointer to the &struct ubi_notification object
|
||||
+ */
|
||||
+static int nvmem_notify(struct notifier_block *nb, unsigned long l,
|
||||
+ void *ns_ptr)
|
||||
+{
|
||||
+ struct ubi_notification *nt = ns_ptr;
|
||||
+
|
||||
+ switch (l) {
|
||||
+ case UBI_VOLUME_RESIZED:
|
||||
+ ubi_nvmem_remove(&nt->vi);
|
||||
+ fallthrough;
|
||||
+ case UBI_VOLUME_ADDED:
|
||||
+ ubi_nvmem_add(&nt->vi);
|
||||
+ break;
|
||||
+ case UBI_VOLUME_SHUTDOWN:
|
||||
+ ubi_nvmem_remove(&nt->vi);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ return NOTIFY_OK;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block nvmem_notifier = {
|
||||
+ .notifier_call = nvmem_notify,
|
||||
+};
|
||||
+
|
||||
+static int __init ubi_nvmem_init(void)
|
||||
+{
|
||||
+ return ubi_register_volume_notifier(&nvmem_notifier, 0);
|
||||
+}
|
||||
+
|
||||
+static void __exit ubi_nvmem_exit(void)
|
||||
+{
|
||||
+ struct ubi_nvmem *unv, *tmp;
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
|
||||
+ nvmem_unregister(unv->nvmem);
|
||||
+ list_del(&unv->list);
|
||||
+ kfree(unv);
|
||||
+ }
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+
|
||||
+ ubi_unregister_volume_notifier(&nvmem_notifier);
|
||||
+}
|
||||
+
|
||||
+module_init(ubi_nvmem_init);
|
||||
+module_exit(ubi_nvmem_exit);
|
||||
+MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
|
||||
+MODULE_AUTHOR("Daniel Golle");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,120 @@
|
||||
From 9ffc1d7d73609a89eb264d6066340f8b7b3b0ebe Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 7 Aug 2023 21:19:45 +0100
|
||||
Subject: [PATCH 08/15] dt-bindings: block: add basic bindings for block
|
||||
devices
|
||||
|
||||
Add bindings for block devices which are used to allow referencing
|
||||
nvmem bits on them.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
.../bindings/block/block-device.yaml | 22 ++++++++
|
||||
.../devicetree/bindings/block/partition.yaml | 50 +++++++++++++++++++
|
||||
.../devicetree/bindings/block/partitions.yaml | 20 ++++++++
|
||||
3 files changed, 92 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
|
||||
create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
|
||||
create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/block/block-device.yaml
|
||||
@@ -0,0 +1,22 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/block/block-device.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: block storage device
|
||||
+
|
||||
+description: |
|
||||
+ This binding is generic and describes a block-oriented storage device.
|
||||
+
|
||||
+maintainers:
|
||||
+ - Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+properties:
|
||||
+ partitions:
|
||||
+ $ref: /schemas/block/partitions.yaml
|
||||
+
|
||||
+ nvmem-layout:
|
||||
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
|
||||
+
|
||||
+unevaluatedProperties: false
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/block/partition.yaml
|
||||
@@ -0,0 +1,50 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/block/partition.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Partition on a block device
|
||||
+
|
||||
+description: |
|
||||
+ This binding describes a partition on a block device.
|
||||
+ Partitions may be matched by a combination of partition number, name,
|
||||
+ and UUID.
|
||||
+
|
||||
+maintainers:
|
||||
+ - Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+properties:
|
||||
+ $nodename:
|
||||
+ pattern: '^block-partition-.+$'
|
||||
+
|
||||
+ partnum:
|
||||
+ description:
|
||||
+ Matches partition by number if present.
|
||||
+
|
||||
+ partname:
|
||||
+ "$ref": "/schemas/types.yaml#/definitions/string"
|
||||
+ description:
|
||||
+ Matches partition by PARTNAME if present.
|
||||
+
|
||||
+ uuid:
|
||||
+ "$ref": "/schemas/types.yaml#/definitions/string"
|
||||
+ description:
|
||||
+ Matches partition by PARTUUID if present.
|
||||
+
|
||||
+ nvmem-layout:
|
||||
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
|
||||
+ description:
|
||||
+ This container may reference an NVMEM layout parser.
|
||||
+
|
||||
+anyOf:
|
||||
+ - required:
|
||||
+ - partnum
|
||||
+
|
||||
+ - required:
|
||||
+ - partname
|
||||
+
|
||||
+ - required:
|
||||
+ - uuid
|
||||
+
|
||||
+unevaluatedProperties: false
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/block/partitions.yaml
|
||||
@@ -0,0 +1,20 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/block/partitions.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Partitions on block devices
|
||||
+
|
||||
+description: |
|
||||
+ This binding is generic and describes the content of the partitions container
|
||||
+ node.
|
||||
+
|
||||
+maintainers:
|
||||
+ - Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+patternProperties:
|
||||
+ "^block-partition-.+$":
|
||||
+ $ref: partition.yaml
|
||||
+
|
||||
+unevaluatedProperties: false
|
@ -0,0 +1,77 @@
|
||||
From 614f4f6fdda09e30ecf7ef6c8091579db15018cb Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Fri, 21 Jul 2023 17:51:03 +0100
|
||||
Subject: [PATCH 09/15] block: partitions: populate fwnode
|
||||
|
||||
Let block partitions to be represented by a firmware node and hence
|
||||
allow them to being referenced e.g. for use with blk-nvmem.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 41 insertions(+)
|
||||
|
||||
--- a/block/partitions/core.c
|
||||
+++ b/block/partitions/core.c
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/raid/detect.h>
|
||||
+#include <linux/property.h>
|
||||
+
|
||||
#include "check.h"
|
||||
|
||||
static int (*check_part[])(struct parsed_partitions *) = {
|
||||
@@ -298,6 +300,43 @@ static ssize_t whole_disk_show(struct de
|
||||
}
|
||||
static DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
|
||||
|
||||
+static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
|
||||
+{
|
||||
+ struct fwnode_handle *fw_parts, *fw_part;
|
||||
+ struct device *ddev = disk_to_dev(bdev->bd_disk);
|
||||
+ const char *partname, *uuid;
|
||||
+ u32 partno;
|
||||
+
|
||||
+ fw_parts = device_get_named_child_node(ddev, "partitions");
|
||||
+ if (!fw_parts)
|
||||
+ fw_parts = device_get_named_child_node(ddev->parent, "partitions");
|
||||
+
|
||||
+ if (!fw_parts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ fwnode_for_each_child_node(fw_parts, fw_part) {
|
||||
+ if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
|
||||
+ (!bdev->bd_meta_info || strncmp(uuid,
|
||||
+ bdev->bd_meta_info->uuid,
|
||||
+ PARTITION_META_INFO_UUIDLTH)))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
|
||||
+ (!bdev->bd_meta_info || strncmp(partname,
|
||||
+ bdev->bd_meta_info->volname,
|
||||
+ PARTITION_META_INFO_VOLNAMELTH)))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
|
||||
+ bdev->bd_partno != partno)
|
||||
+ continue;
|
||||
+
|
||||
+ return fw_part;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Must be called either with open_mutex held, before a disk can be opened or
|
||||
* after all disk users are gone.
|
||||
@@ -380,6 +419,8 @@ static struct block_device *add_partitio
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
+ device_set_node(pdev, find_partition_fwnode(bdev));
|
||||
+
|
||||
/* delay uevent until 'holders' subdir is created */
|
||||
dev_set_uevent_suppress(pdev, 1);
|
||||
err = device_add(pdev);
|
@ -0,0 +1,29 @@
|
||||
From 65f3ff9672ccd5ee78937047e7a2fc696eee1c8f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 13 Jul 2023 04:07:16 +0100
|
||||
Subject: [PATCH 10/15] block: add new genhd flag GENHD_FL_NVMEM
|
||||
|
||||
Add new flag to destinguish block devices which may act as an NVMEM
|
||||
provider.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
include/linux/blkdev.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/include/linux/blkdev.h
|
||||
+++ b/include/linux/blkdev.h
|
||||
@@ -87,11 +87,13 @@ struct partition_meta_info {
|
||||
* ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
|
||||
* scan for partitions from add_disk, and users can't add partitions manually.
|
||||
*
|
||||
+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
|
||||
*/
|
||||
enum {
|
||||
GENHD_FL_REMOVABLE = 1 << 0,
|
||||
GENHD_FL_HIDDEN = 1 << 1,
|
||||
GENHD_FL_NO_PART = 1 << 2,
|
||||
+ GENHD_FL_NVMEM = 1 << 3,
|
||||
};
|
||||
|
||||
enum {
|
@ -0,0 +1,235 @@
|
||||
From b9936aa8a3775c2027f655d91a206d0e6e1c7ec0 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 11 Jul 2023 00:17:31 +0100
|
||||
Subject: [PATCH 11/15] block: implement NVMEM provider
|
||||
|
||||
On embedded devices using an eMMC it is common that one or more partitions
|
||||
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
|
||||
data. Allow referencing the partition in device tree for the kernel and
|
||||
Wi-Fi drivers accessing it via the NVMEM layer.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
block/Kconfig | 9 +++
|
||||
block/Makefile | 1 +
|
||||
block/blk-nvmem.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 196 insertions(+)
|
||||
create mode 100644 block/blk-nvmem.c
|
||||
|
||||
--- a/block/Kconfig
|
||||
+++ b/block/Kconfig
|
||||
@@ -203,6 +203,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
|
||||
by falling back to the kernel crypto API when inline
|
||||
encryption hardware is not present.
|
||||
|
||||
+config BLK_NVMEM
|
||||
+ bool "Block device NVMEM provider"
|
||||
+ depends on OF
|
||||
+ depends on NVMEM
|
||||
+ help
|
||||
+ Allow block devices (or partitions) to act as NVMEM prodivers,
|
||||
+ typically used with eMMC to store MAC addresses or Wi-Fi
|
||||
+ calibration data on embedded devices.
|
||||
+
|
||||
source "block/partitions/Kconfig"
|
||||
|
||||
config BLOCK_COMPAT
|
||||
--- a/block/Makefile
|
||||
+++ b/block/Makefile
|
||||
@@ -35,6 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned
|
||||
obj-$(CONFIG_BLK_WBT) += blk-wbt.o
|
||||
obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
|
||||
obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
|
||||
+obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
|
||||
obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
|
||||
obj-$(CONFIG_BLK_PM) += blk-pm.o
|
||||
obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
|
||||
--- /dev/null
|
||||
+++ b/block/blk-nvmem.c
|
||||
@@ -0,0 +1,186 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * block device NVMEM provider
|
||||
+ *
|
||||
+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
|
||||
+ *
|
||||
+ * Useful on devices using a partition on an eMMC for MAC addresses or
|
||||
+ * Wi-Fi calibration EEPROM data.
|
||||
+ */
|
||||
+
|
||||
+#include "blk.h"
|
||||
+#include <linux/nvmem-provider.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/pagemap.h>
|
||||
+#include <linux/property.h>
|
||||
+
|
||||
+/* List of all NVMEM devices */
|
||||
+static LIST_HEAD(nvmem_devices);
|
||||
+static DEFINE_MUTEX(devices_mutex);
|
||||
+
|
||||
+struct blk_nvmem {
|
||||
+ struct nvmem_device *nvmem;
|
||||
+ struct block_device *bdev;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+static int blk_nvmem_reg_read(void *priv, unsigned int from,
|
||||
+ void *val, size_t bytes)
|
||||
+{
|
||||
+ unsigned long offs = from & ~PAGE_MASK, to_read;
|
||||
+ pgoff_t f_index = from >> PAGE_SHIFT;
|
||||
+ struct address_space *mapping;
|
||||
+ struct blk_nvmem *bnv = priv;
|
||||
+ size_t bytes_left = bytes;
|
||||
+ struct folio *folio;
|
||||
+ void *p;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!bnv->bdev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (!bnv->bdev->bd_disk)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!bnv->bdev->bd_disk->fops)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ if (!bnv->bdev->bd_disk->fops->open)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev, FMODE_READ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ mapping = bnv->bdev->bd_inode->i_mapping;
|
||||
+
|
||||
+ while (bytes_left) {
|
||||
+ folio = read_mapping_folio(mapping, f_index++, NULL);
|
||||
+ if (IS_ERR(folio)) {
|
||||
+ ret = PTR_ERR(folio);
|
||||
+ goto err_release_bdev;
|
||||
+ }
|
||||
+ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
|
||||
+ p = folio_address(folio) + offset_in_folio(folio, offs);
|
||||
+ memcpy(val, p, to_read);
|
||||
+ offs = 0;
|
||||
+ bytes_left -= to_read;
|
||||
+ val += to_read;
|
||||
+ folio_put(folio);
|
||||
+ }
|
||||
+
|
||||
+err_release_bdev:
|
||||
+ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk, FMODE_READ);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int blk_nvmem_register(struct device *dev, struct class_interface *iface)
|
||||
+{
|
||||
+ struct device_node *np = dev_of_node(dev);
|
||||
+ struct block_device *bdev = dev_to_bdev(dev);
|
||||
+ struct nvmem_config config = {};
|
||||
+ struct blk_nvmem *bnv;
|
||||
+
|
||||
+ /* skip devices which do not have a device tree node */
|
||||
+ if (!np)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* skip devices without an nvmem layout defined */
|
||||
+ if (!of_get_child_by_name(np, "nvmem-layout"))
|
||||
+ return 0;
|
||||
+
|
||||
+ /*
|
||||
+ * skip devices which don't have GENHD_FL_NVMEM set
|
||||
+ *
|
||||
+ * This flag is used for mtdblock and ubiblock devices because
|
||||
+ * both, MTD and UBI already implement their own NVMEM provider.
|
||||
+ * To avoid registering multiple NVMEM providers for the same
|
||||
+ * device node, don't register the block NVMEM provider for them.
|
||||
+ */
|
||||
+ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
|
||||
+ return 0;
|
||||
+
|
||||
+ /*
|
||||
+ * skip block device too large to be represented as NVMEM devices
|
||||
+ * which are using an 'int' as address
|
||||
+ */
|
||||
+ if (bdev_nr_bytes(bdev) > INT_MAX)
|
||||
+ return -EFBIG;
|
||||
+
|
||||
+ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
|
||||
+ if (!bnv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ config.id = NVMEM_DEVID_NONE;
|
||||
+ config.dev = &bdev->bd_device;
|
||||
+ config.name = dev_name(&bdev->bd_device);
|
||||
+ config.owner = THIS_MODULE;
|
||||
+ config.priv = bnv;
|
||||
+ config.reg_read = blk_nvmem_reg_read;
|
||||
+ config.size = bdev_nr_bytes(bdev);
|
||||
+ config.word_size = 1;
|
||||
+ config.stride = 1;
|
||||
+ config.read_only = true;
|
||||
+ config.root_only = true;
|
||||
+ config.ignore_wp = true;
|
||||
+ config.of_node = to_of_node(dev->fwnode);
|
||||
+
|
||||
+ bnv->bdev = bdev;
|
||||
+ bnv->nvmem = nvmem_register(&config);
|
||||
+ if (IS_ERR(bnv->nvmem)) {
|
||||
+ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
|
||||
+ "Failed to register NVMEM device\n");
|
||||
+
|
||||
+ kfree(bnv);
|
||||
+ return PTR_ERR(bnv->nvmem);
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ list_add_tail(&bnv->list, &nvmem_devices);
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void blk_nvmem_unregister(struct device *dev, struct class_interface *iface)
|
||||
+{
|
||||
+ struct block_device *bdev = dev_to_bdev(dev);
|
||||
+ struct blk_nvmem *bnv_c, *bnv = NULL;
|
||||
+
|
||||
+ mutex_lock(&devices_mutex);
|
||||
+ list_for_each_entry(bnv_c, &nvmem_devices, list) {
|
||||
+ if (bnv_c->bdev == bdev) {
|
||||
+ bnv = bnv_c;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!bnv) {
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ list_del(&bnv->list);
|
||||
+ mutex_unlock(&devices_mutex);
|
||||
+ nvmem_unregister(bnv->nvmem);
|
||||
+ kfree(bnv);
|
||||
+}
|
||||
+
|
||||
+static struct class_interface blk_nvmem_bus_interface __refdata = {
|
||||
+ .class = &block_class,
|
||||
+ .add_dev = &blk_nvmem_register,
|
||||
+ .remove_dev = &blk_nvmem_unregister,
|
||||
+};
|
||||
+
|
||||
+static int __init blk_nvmem_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = class_interface_register(&blk_nvmem_bus_interface);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+device_initcall(blk_nvmem_init);
|
@ -0,0 +1,74 @@
|
||||
From 86864bf8f40e84dc881c197ef470a88668329dbf Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Mon, 7 Aug 2023 21:21:45 +0100
|
||||
Subject: [PATCH 12/15] dt-bindings: mmc: mmc-card: add block device nodes
|
||||
|
||||
Add nodes representing the block devices exposed by an MMC device
|
||||
including an example involving nvmem-cells.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
.../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
|
||||
1 file changed, 45 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
|
||||
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
|
||||
@@ -26,6 +26,18 @@ properties:
|
||||
Use this to indicate that the mmc-card has a broken hpi
|
||||
implementation, and that hpi should not be used.
|
||||
|
||||
+ block:
|
||||
+ $ref: /schemas/block/block-device.yaml#
|
||||
+ description:
|
||||
+ Represents the block storage provided by an SD card or the
|
||||
+ main hardware partition of an eMMC.
|
||||
+
|
||||
+patternProperties:
|
||||
+ '^boot[0-9]+':
|
||||
+ $ref: /schemas/block/block-device.yaml#
|
||||
+ description:
|
||||
+ Represents a boot hardware partition on an eMMC.
|
||||
+
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -42,6 +54,39 @@ examples:
|
||||
compatible = "mmc-card";
|
||||
reg = <0>;
|
||||
broken-hpi;
|
||||
+
|
||||
+ block {
|
||||
+ partitions {
|
||||
+ cal_data: block-partition-rf {
|
||||
+ partnum = <3>;
|
||||
+ partname = "rf";
|
||||
+
|
||||
+ nvmem-layout {
|
||||
+ compatible = "fixed-layout";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+
|
||||
+ eeprom@0 {
|
||||
+ reg = <0x0 0x1000>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ boot1 {
|
||||
+ nvmem-layout {
|
||||
+ compatible = "fixed-layout";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+
|
||||
+ macaddr: macaddr@a {
|
||||
+ compatible = "mac-base";
|
||||
+ reg = <0xa 0x6>;
|
||||
+ #nvmem-cell-cells = <1>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,23 @@
|
||||
From 644942a31719de674e2aa68f83d66bd8ae7e4fb7 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 13 Jul 2023 04:12:21 +0100
|
||||
Subject: [PATCH 13/15] mmc: core: set card fwnode_handle
|
||||
|
||||
Set fwnode in case it isn't set yet and of_node is present.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mmc/core/bus.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mmc/core/bus.c
|
||||
+++ b/drivers/mmc/core/bus.c
|
||||
@@ -363,6 +363,8 @@ int mmc_add_card(struct mmc_card *card)
|
||||
mmc_add_card_debugfs(card);
|
||||
#endif
|
||||
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
|
||||
+ if (card->dev.of_node && !card->dev.fwnode)
|
||||
+ card->dev.fwnode = &card->dev.of_node->fwnode;
|
||||
|
||||
device_enable_async_suspend(&card->dev);
|
||||
|
@ -0,0 +1,38 @@
|
||||
From d9143f86330dd038fc48878558dd287ceee5d3d4 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 13 Jul 2023 04:13:04 +0100
|
||||
Subject: [PATCH 14/15] mmc: block: set fwnode of disk devices
|
||||
|
||||
Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
|
||||
the mmc-card. This is done in preparation for having the eMMC act as
|
||||
NVMEM provider.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mmc/core/block.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/mmc/core/block.c
|
||||
+++ b/drivers/mmc/core/block.c
|
||||
@@ -2484,6 +2484,8 @@ static struct mmc_blk_data *mmc_blk_allo
|
||||
int area_type,
|
||||
unsigned int part_type)
|
||||
{
|
||||
+ struct fwnode_handle *fwnode;
|
||||
+ struct device *ddev;
|
||||
struct mmc_blk_data *md;
|
||||
int devidx, ret;
|
||||
char cap_str[10];
|
||||
@@ -2580,6 +2582,12 @@ static struct mmc_blk_data *mmc_blk_allo
|
||||
|
||||
blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);
|
||||
|
||||
+ ddev = disk_to_dev(md->disk);
|
||||
+ fwnode = device_get_named_child_node(subname ? md->parent->parent :
|
||||
+ md->parent,
|
||||
+ subname ? subname : "block");
|
||||
+ ddev->fwnode = fwnode;
|
||||
+
|
||||
string_get_size((u64)size, 512, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
pr_info("%s: %s %s %s %s\n",
|
@ -0,0 +1,22 @@
|
||||
From 322035ab2b0113d98b6c0ea788d971e0df2952a4 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 20 Jul 2023 17:36:44 +0100
|
||||
Subject: [PATCH 15/15] mmc: block: set GENHD_FL_NVMEM
|
||||
|
||||
Set flag to consider MMC block devices as NVMEM providers.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mmc/core/block.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mmc/core/block.c
|
||||
+++ b/drivers/mmc/core/block.c
|
||||
@@ -2538,6 +2538,7 @@ static struct mmc_blk_data *mmc_blk_allo
|
||||
md->disk->major = MMC_BLOCK_MAJOR;
|
||||
md->disk->minors = perdev_minors;
|
||||
md->disk->first_minor = devidx * perdev_minors;
|
||||
+ md->disk->flags = GENHD_FL_NVMEM;
|
||||
md->disk->fops = &mmc_bdops;
|
||||
md->disk->private_data = md;
|
||||
md->parent = parent;
|
@ -8,10 +8,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/mtd/ubi/build.c
|
||||
+++ b/drivers/mtd/ubi/build.c
|
||||
@@ -1213,6 +1213,73 @@ static struct mtd_info * __init open_mtd
|
||||
return mtd;
|
||||
}
|
||||
@@ -1263,6 +1263,74 @@ static struct mtd_notifier ubi_mtd_notif
|
||||
.remove = ubi_notify_remove,
|
||||
};
|
||||
|
||||
+
|
||||
+/*
|
||||
+ * This function tries attaching mtd partitions named either "ubi" or "data"
|
||||
+ * during boot.
|
||||
@ -79,10 +80,10 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ put_mtd_device(mtd);
|
||||
+}
|
||||
+
|
||||
static int __init ubi_init(void)
|
||||
static int __init ubi_init_attach(void)
|
||||
{
|
||||
int err, i, k;
|
||||
@@ -1297,6 +1364,12 @@ static int __init ubi_init(void)
|
||||
@@ -1313,6 +1381,12 @@ static int __init ubi_init_attach(void)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +93,6 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ !ubi_is_module() && !mtd_devs)
|
||||
+ ubi_auto_attach();
|
||||
+
|
||||
err = ubiblock_init();
|
||||
if (err) {
|
||||
pr_err("UBI error: block: cannot initialize, error %d\n", err);
|
||||
return 0;
|
||||
|
||||
out_detach:
|
||||
|
@ -8,8 +8,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -653,6 +653,47 @@ static void __init ubiblock_create_from_
|
||||
}
|
||||
@@ -644,10 +644,47 @@ match_volume_desc(struct ubi_volume_info
|
||||
return true;
|
||||
}
|
||||
|
||||
+#define UBIFS_NODE_MAGIC 0x06101831
|
||||
@ -24,46 +24,54 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+ return magic == UBIFS_NODE_MAGIC;
|
||||
+}
|
||||
+
|
||||
+static void __init ubiblock_create_auto_rootfs(void)
|
||||
+static void __init ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
|
||||
+{
|
||||
+ int ubi_num, ret, is_ubifs;
|
||||
+ int ret, is_ubifs;
|
||||
+ struct ubi_volume_desc *desc;
|
||||
+ struct ubi_volume_info vi;
|
||||
+
|
||||
+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
|
||||
+ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
|
||||
+ if (IS_ERR(desc))
|
||||
+ desc = ubi_open_volume_nm(ubi_num, "fit", UBI_READONLY);;
|
||||
+ if (strcmp(vi->name, "rootfs") &&
|
||||
+ strcmp(vi->name, "fit"))
|
||||
+ return;
|
||||
+
|
||||
+ if (IS_ERR(desc))
|
||||
+ continue;
|
||||
+ desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY);
|
||||
+ if (IS_ERR(desc))
|
||||
+ return;
|
||||
+
|
||||
+ ubi_get_volume_info(desc, &vi);
|
||||
+ is_ubifs = ubi_vol_is_ubifs(desc);
|
||||
+ ubi_close_volume(desc);
|
||||
+ if (is_ubifs)
|
||||
+ break;
|
||||
+ is_ubifs = ubi_vol_is_ubifs(desc);
|
||||
+ ubi_close_volume(desc);
|
||||
+ if (is_ubifs)
|
||||
+ return;
|
||||
+
|
||||
+ ret = ubiblock_create(&vi);
|
||||
+ if (ret)
|
||||
+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
|
||||
+ vi.name, ret);
|
||||
+ /* always break if we get here */
|
||||
+ break;
|
||||
+ }
|
||||
+ ret = ubiblock_create(vi);
|
||||
+ if (ret)
|
||||
+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
|
||||
+ vi->name, ret);
|
||||
+}
|
||||
+
|
||||
static void ubiblock_remove_all(void)
|
||||
static void
|
||||
ubiblock_create_from_param(struct ubi_volume_info *vi)
|
||||
{
|
||||
struct ubiblock *next;
|
||||
@@ -685,6 +726,10 @@ int __init ubiblock_init(void)
|
||||
*/
|
||||
ubiblock_create_from_param();
|
||||
int i, ret = 0;
|
||||
+ bool got_param = false;
|
||||
struct ubiblock_param *p;
|
||||
|
||||
+ /* auto-attach "rootfs" volume if existing and non-ubifs */
|
||||
+ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
|
||||
+ ubiblock_create_auto_rootfs();
|
||||
+
|
||||
/*
|
||||
* Block devices are only created upon user requests, so we ignore
|
||||
* existing volumes.
|
||||
@@ -660,6 +697,7 @@ ubiblock_create_from_param(struct ubi_vo
|
||||
if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
|
||||
continue;
|
||||
|
||||
+ got_param = true;
|
||||
ret = ubiblock_create(vi);
|
||||
if (ret) {
|
||||
pr_err(
|
||||
@@ -668,6 +706,10 @@ ubiblock_create_from_param(struct ubi_vo
|
||||
}
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ /* auto-attach "rootfs" volume if existing and non-ubifs */
|
||||
+ if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
|
||||
+ ubiblock_create_auto_rootfs(vi);
|
||||
}
|
||||
|
||||
static int ubiblock_notify(struct notifier_block *nb,
|
||||
|
@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -42,6 +42,7 @@
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/idr.h>
|
||||
#include <asm/div64.h>
|
||||
@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
#include "ubi-media.h"
|
||||
#include "ubi.h"
|
||||
@@ -459,6 +460,15 @@ int ubiblock_create(struct ubi_volume_in
|
||||
@@ -460,6 +461,15 @@ int ubiblock_create(struct ubi_volume_in
|
||||
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
|
||||
dev->ubi_num, dev->vol_id, vi->name);
|
||||
mutex_unlock(&devices_mutex);
|
||||
|
@ -50,7 +50,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
break;
|
||||
--- a/drivers/mtd/ubi/ubi.h
|
||||
+++ b/drivers/mtd/ubi/ubi.h
|
||||
@@ -778,6 +778,7 @@ struct ubi_attach_info {
|
||||
@@ -780,6 +780,7 @@ struct ubi_attach_info {
|
||||
int mean_ec;
|
||||
uint64_t ec_sum;
|
||||
int ec_count;
|
||||
|
@ -72,18 +72,17 @@ Subject: [PATCH] kernel: add block fit partition parser
|
||||
+int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain);
|
||||
--- a/block/partitions/core.c
|
||||
+++ b/block/partitions/core.c
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <linux/ctype.h>
|
||||
@@ -11,6 +11,9 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/raid/detect.h>
|
||||
#include <linux/property.h>
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+#include <linux/root_dev.h>
|
||||
+#endif
|
||||
+
|
||||
|
||||
#include "check.h"
|
||||
|
||||
static int (*check_part[])(struct parsed_partitions *) = {
|
||||
@@ -46,6 +50,9 @@ static int (*check_part[])(struct parsed
|
||||
@@ -48,6 +51,9 @@ static int (*check_part[])(struct parsed
|
||||
#ifdef CONFIG_EFI_PARTITION
|
||||
efi_partition, /* this must come before msdos */
|
||||
#endif
|
||||
@ -93,7 +92,7 @@ Subject: [PATCH] kernel: add block fit partition parser
|
||||
#ifdef CONFIG_SGI_PARTITION
|
||||
sgi_partition,
|
||||
#endif
|
||||
@@ -398,6 +405,11 @@ static struct block_device *add_partitio
|
||||
@@ -439,6 +445,11 @@ static struct block_device *add_partitio
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
@ -105,7 +104,7 @@ Subject: [PATCH] kernel: add block fit partition parser
|
||||
/* everything is up and running, commence */
|
||||
err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
|
||||
if (err)
|
||||
@@ -590,6 +602,11 @@ static bool blk_add_partition(struct gen
|
||||
@@ -631,6 +642,11 @@ static bool blk_add_partition(struct gen
|
||||
(state->parts[p].flags & ADDPART_FLAG_RAID))
|
||||
md_autodetect_dev(part->bd_dev);
|
||||
|
||||
@ -194,7 +193,7 @@ Subject: [PATCH] kernel: add block fit partition parser
|
||||
set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -431,7 +431,9 @@ int ubiblock_create(struct ubi_volume_in
|
||||
@@ -432,7 +432,9 @@ int ubiblock_create(struct ubi_volume_in
|
||||
ret = -ENODEV;
|
||||
goto out_cleanup_disk;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user