dm: disk: add UCLASS_PARTITION
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 19 Apr 2022 01:05:09 +0000 (10:05 +0900)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Sat, 23 Apr 2022 20:05:41 +0000 (22:05 +0200)
NOTE: probably we have to update config dependencies,
in particular, SPL/TPL_PRINTF?

With this new function, UCLASS_PARTITION devices will be created as
child nodes of UCLASS_BLK device.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
disk/Makefile
disk/disk-uclass.c [new file with mode: 0644]
include/dm/uclass-id.h
include/part.h

index 5ca10c5..ec14883 100644 (file)
@@ -6,6 +6,9 @@
 #ccflags-y += -DET_DEBUG -DDEBUG
 
 obj-$(CONFIG_$(SPL_TPL_)PARTITIONS)  += part.o
+ifdef CONFIG_$(SPL_TPL_)BLK
+obj-$(CONFIG_$(SPL_TPL_)PARTITIONS)  += disk-uclass.o
+endif
 obj-$(CONFIG_$(SPL_TPL_)MAC_PARTITION)   += part_mac.o
 obj-$(CONFIG_$(SPL_TPL_)DOS_PARTITION)   += part_dos.o
 obj-$(CONFIG_$(SPL_TPL_)ISO_PARTITION)   += part_iso.o
diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c
new file mode 100644 (file)
index 0000000..4918a2f
--- /dev/null
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Software partition device (UCLASS_PARTITION)
+ *
+ *  Copyright (c) 2021 Linaro Limited
+ *                     Author: AKASHI Takahiro
+ */
+
+#define LOG_CATEGORY UCLASS_PARTITION
+
+#include <blk.h>
+#include <dm.h>
+#include <log.h>
+#include <part.h>
+#include <vsprintf.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+int part_create_block_devices(struct udevice *blk_dev)
+{
+       int part, count;
+       struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
+       struct disk_partition info;
+       struct disk_part *part_data;
+       char devname[32];
+       struct udevice *dev;
+       int ret;
+
+       if (!CONFIG_IS_ENABLED(PARTITIONS) ||
+           !CONFIG_IS_ENABLED(HAVE_BLOCK_DEVICE))
+               return 0;
+
+       if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
+               return 0;
+
+       /* Add devices for each partition */
+       for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+               if (part_get_info(desc, part, &info))
+                       continue;
+               snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
+                        part);
+
+               ret = device_bind_driver(blk_dev, "blk_partition",
+                                        strdup(devname), &dev);
+               if (ret)
+                       return ret;
+
+               part_data = dev_get_uclass_plat(dev);
+               part_data->partnum = part;
+               part_data->gpt_part_info = info;
+               count++;
+
+               ret = device_probe(dev);
+               if (ret) {
+                       debug("Can't probe\n");
+                       count--;
+                       device_unbind(dev);
+
+                       continue;
+               }
+       }
+       debug("%s: %d partitions found in %s\n", __func__, count,
+             blk_dev->name);
+
+       return 0;
+}
+
+static ulong blk_part_read(struct udevice *dev, lbaint_t start,
+                          lbaint_t blkcnt, void *buffer)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->read)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->read(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_write(struct udevice *dev, lbaint_t start,
+                           lbaint_t blkcnt, const void *buffer)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->write)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->write(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_erase(struct udevice *dev, lbaint_t start,
+                           lbaint_t blkcnt)
+{
+       struct udevice *parent;
+       struct disk_part *part;
+       const struct blk_ops *ops;
+
+       parent = dev_get_parent(dev);
+       ops = blk_get_ops(parent);
+       if (!ops->erase)
+               return -ENOSYS;
+
+       part = dev_get_uclass_plat(dev);
+       if (start >= part->gpt_part_info.size)
+               return 0;
+
+       if ((start + blkcnt) > part->gpt_part_info.size)
+               blkcnt = part->gpt_part_info.size - start;
+       start += part->gpt_part_info.start;
+
+       return ops->erase(parent, start, blkcnt);
+}
+
+static const struct blk_ops blk_part_ops = {
+       .read   = blk_part_read,
+       .write  = blk_part_write,
+       .erase  = blk_part_erase,
+};
+
+U_BOOT_DRIVER(blk_partition) = {
+       .name           = "blk_partition",
+       .id             = UCLASS_PARTITION,
+       .ops            = &blk_part_ops,
+};
+
+UCLASS_DRIVER(partition) = {
+       .id             = UCLASS_PARTITION,
+       .per_device_plat_auto   = sizeof(struct disk_part),
+       .name           = "partition",
+};
index 0e26e1d..230b1ea 100644 (file)
@@ -83,6 +83,7 @@ enum uclass_id {
        UCLASS_P2SB,            /* (x86) Primary-to-Sideband Bus */
        UCLASS_PANEL,           /* Display panel, such as an LCD */
        UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */
+       UCLASS_PARTITION,       /* Logical disk partition device */
        UCLASS_PCH,             /* x86 platform controller hub */
        UCLASS_PCI,             /* PCI bus */
        UCLASS_PCI_EP,          /* PCI endpoint device */
index 625afe7..a8db398 100644 (file)
@@ -303,6 +303,16 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
 }
 #endif
 
+struct udevice;
+/**
+ * part_create_block_devices - Create block devices for disk partitions
+ *
+ * Create UCLASS_PARTITION udevices for each of disk partitions in @parent
+ *
+ * @blk_dev:   Whole disk device
+ */
+int part_create_block_devices(struct udevice *blk_dev);
+
 /*
  * We don't support printing partition information in SPL and only support
  * getting partition information in a few cases.