From: Sam Edwards <cfsworks@gmail.com>
To: Heiko Schocher <hs@denx.de>, Kyungmin Park <kmpark@infradead.org>
Cc: u-boot@lists.denx.de, Sam Edwards <CFSworks@gmail.com>
Subject: [RFC PATCH 2/4] mtd: ubi: bind block device driver for static volumes
Date: Fri, 11 Aug 2023 18:06:04 -0600 [thread overview]
Message-ID: <20230812000606.72319-3-CFSworks@gmail.com> (raw)
In-Reply-To: <20230812000606.72319-1-CFSworks@gmail.com>
This makes static UBI volumes readable as block devices, however
no mechanism for selecting these volume devices yet exists.
Signed-off-by: Sam Edwards <CFSworks@gmail.com>
---
drivers/mtd/ubi/ubi-uclass.c | 110 +++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/drivers/mtd/ubi/ubi-uclass.c b/drivers/mtd/ubi/ubi-uclass.c
index f8971e793e..231d6d90c7 100644
--- a/drivers/mtd/ubi/ubi-uclass.c
+++ b/drivers/mtd/ubi/ubi-uclass.c
@@ -8,10 +8,119 @@
#define LOG_CATEGORY UCLASS_UBI
#include <common.h>
+#include <blk.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <ubi_uboot.h>
+static ulong ubi_bread(struct udevice *dev, lbaint_t lba, lbaint_t blkcnt,
+ void *dst)
+{
+ int err, lnum;
+ struct blk_desc *blk = dev_get_uclass_plat(dev);
+ struct ubi_device *ubi = dev_get_plat(dev->parent);
+ struct ubi_volume *vol = ubi->volumes[blk->devnum];
+ lbaint_t lba_per_peb = vol->usable_leb_size / blk->blksz;
+ lbaint_t lba_off, lba_len, total = 0;
+
+ while (blkcnt) {
+ lnum = lba / lba_per_peb;
+ lba_off = lba % lba_per_peb;
+ lba_len = lba_per_peb - lba_off;
+ if (lba_len > blkcnt)
+ lba_len = blkcnt;
+
+ err = ubi_eba_read_leb(ubi, vol, lnum, dst,
+ lba_off << blk->log2blksz,
+ lba_len << blk->log2blksz, 0);
+ if (err) {
+ pr_err("UBI read error %x\n", err);
+ break;
+ }
+
+ lba += lba_len;
+ blkcnt -= lba_len;
+ dst += lba_len << blk->log2blksz;
+ total += lba_len;
+ }
+
+ return total;
+}
+
+static const struct blk_ops ubi_block_ops = {
+ .read = ubi_bread,
+};
+
+U_BOOT_DRIVER(ubi_block) = {
+ .name = "ubi_block",
+ .id = UCLASS_BLK,
+ .ops = &ubi_block_ops,
+};
+
+static bool is_power_of_two(unsigned int x)
+{
+ return (x & -x) == x;
+}
+
+static unsigned int choose_blksz_for_volume(const struct ubi_volume *vol)
+{
+ /*
+ * U-Boot assumes a power-of-two blksz; however, UBI LEBs are
+ * very often not suitably sized. To solve this, we divide the
+ * LEBs into a whole number of LBAs per LEB, such that each LBA
+ * addresses a power-of-two-sized block. To choose the blksz,
+ * we either:
+ * 1) Use the volume alignment, if it's a non-unity power of
+ * two. The LEB size is a multiple of this alignment, and it
+ * allows the user to force a particular blksz if needed for
+ * their use case.
+ * 2) Otherwise, find the greatest power-of-two factor of the
+ * LEB size.
+ */
+ if (vol->alignment > 1 && is_power_of_two(vol->alignment))
+ return vol->alignment;
+
+ unsigned int blksz = 1;
+ while ((vol->usable_leb_size & blksz) == 0)
+ blksz <<= 1;
+ return blksz;
+}
+
+static int ubi_post_bind(struct udevice *dev)
+{
+ int i;
+ int ret;
+ unsigned int blksz;
+ lbaint_t lba;
+ struct ubi_device *ubi = dev_get_plat(dev);
+
+ for (i = 0; i < ubi->vtbl_slots; i++) {
+ struct ubi_volume *vol = ubi->volumes[i];
+ if (!vol || vol->vol_id >= UBI_INTERNAL_VOL_START ||
+ vol->vol_type != UBI_STATIC_VOLUME)
+ continue;
+
+ if (vol->updating || vol->upd_marker) {
+ pr_err("** UBI volume %d (\"%s\") midupdate; ignored\n",
+ vol->vol_id, vol->name);
+ continue;
+ }
+
+ blksz = choose_blksz_for_volume(vol);
+ lba = DIV_ROUND_UP((unsigned long long)vol->used_bytes, blksz);
+
+ pr_debug("UBI volume %d (\"%s\"): %lu blocks, %d bytes each\n",
+ vol->vol_id, vol->name, lba, blksz);
+
+ ret = blk_create_device(dev, "ubi_block", vol->name, UCLASS_UBI,
+ vol->vol_id, blksz, lba, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
int ubi_dm_bind(unsigned int index)
{
struct udevice *dev;
@@ -71,4 +180,5 @@ U_BOOT_DRIVER(ubi) = {
UCLASS_DRIVER(ubi) = {
.id = UCLASS_UBI,
.name = "ubi",
+ .post_bind = ubi_post_bind,
};
--
2.41.0
next prev parent reply other threads:[~2023-08-12 0:06 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-12 0:06 [RFC PATCH 0/4] mtd: ubi: Enable accessing RO filesystems in UBI vols Sam Edwards
2023-08-12 0:06 ` [RFC PATCH 1/4] mtd: ubi: register UBI attachments as DM devices Sam Edwards
2023-08-12 0:06 ` Sam Edwards [this message]
2023-08-12 0:06 ` [RFC PATCH 3/4] disk: part: fall-through if "ubi" requested but ubifs not mounted Sam Edwards
2023-08-12 0:06 ` [RFC PATCH 4/4] HACK: enable access to `ubi 0:volname` block devices Sam Edwards
2023-08-14 6:45 ` [RFC PATCH 0/4] mtd: ubi: Enable accessing RO filesystems in UBI vols Heiko Schocher
2023-09-07 21:46 ` Sam Edwards
2023-09-21 6:44 ` Heiko Schocher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230812000606.72319-3-CFSworks@gmail.com \
--to=cfsworks@gmail.com \
--cc=hs@denx.de \
--cc=kmpark@infradead.org \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.