summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-02-18 12:59:21 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2022-02-18 12:59:21 +0100
commit9481ada6ad354cfe38418354afee48ceca438c05 (patch)
treee030cda328c36643b1c5085c9be7c5f2210f579b /drivers
parenta32d0e18fb1bc738ae1aa79d8713b178c977988c (diff)
parenteedf7a3b5f990dff893b54740ceea917c24e2cb7 (diff)
downloadbarebox-9481ada6ad354cfe38418354afee48ceca438c05.tar.gz
barebox-9481ada6ad354cfe38418354afee48ceca438c05.tar.xz
Merge branch 'for-next/efi'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/driver.c30
-rw-r--r--drivers/misc/Kconfig23
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/storage-by-uuid.c199
-rw-r--r--drivers/of/base.c2
-rw-r--r--drivers/of/platform.c3
-rw-r--r--drivers/usb/core/usb.c1
7 files changed, 257 insertions, 2 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index f54f4d0b37..2347b5c71f 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -270,6 +270,36 @@ int unregister_device(struct device_d *old_dev)
}
EXPORT_SYMBOL(unregister_device);
+/**
+ * free_device_res - free dynamically allocated device members
+ * @dev: The device
+ *
+ * This frees dynamically allocated resources allocated during device
+ * lifetime, but not the device itself.
+ */
+void free_device_res(struct device_d *dev)
+{
+ free(dev->name);
+ dev->name = NULL;
+ free(dev->unique_name);
+ dev->unique_name = NULL;
+}
+EXPORT_SYMBOL(free_device_res);
+
+/**
+ * free_device - free a device
+ * @dev: The device
+ *
+ * This frees dynamically allocated resources allocated during device
+ * lifetime and finally the device itself.
+ */
+void free_device(struct device_d *dev)
+{
+ free_device_res(dev);
+ free(dev);
+}
+EXPORT_SYMBOL(free_device);
+
/*
* Loop over list of deferred devices as long as at least one
* device is successfully probed. Devices that again request
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5ab0506cd9..78c9c193d8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -47,4 +47,27 @@ config STARFIVE_PWRSEQ
be accessed over /dev/mem or used from kernels which still depend
on bootloader for initialization.
+config STORAGE_BY_UUID
+ bool "storage by UUID"
+ depends on OFDEVICE
+ help
+ This adds a driver which matches to a "barebox,storage-by-uuid"
+ compatible node. The driver looks for a storage device matching the
+ given UUID and when found registers a new cdev for the device.
+
+ This driver solved a very specific problem. On EFI the storage devices
+ are not connected to any device tree node. barebox-state however expects
+ a node to use as its backend. The obvious solution would be to create
+ a partition with a specific partuuid and use that for state, in our
+ special usecase though the storage device is partitioned with a MBR
+ which doesn't have any space left to create a new partition. As this
+ driver parses the of partition binding we can use that to create
+ a partition in an unallocated are of the disk which is then used for
+ state.
+
+ This driver has the problem that it depends on storage devices which
+ are not described in the device tree. This means it cannot work with
+ deep probe. This is not a problem on EFI though. It's a special purpose
+ driver, it's not recommended for general use.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6326e784fc..986f7b1b38 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_STATE_DRV) += state.o
obj-$(CONFIG_DEV_MEM) += mem.o
obj-$(CONFIG_UBOOTVAR) += ubootvar.o
obj-$(CONFIG_STARFIVE_PWRSEQ) += starfive-pwrseq.o
+obj-$(CONFIG_STORAGE_BY_UUID) += storage-by-uuid.o
diff --git a/drivers/misc/storage-by-uuid.c b/drivers/misc/storage-by-uuid.c
new file mode 100644
index 0000000000..12a06076a2
--- /dev/null
+++ b/drivers/misc/storage-by-uuid.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <malloc.h>
+#include <partition.h>
+#include <envfs.h>
+#include <fs.h>
+
+static LIST_HEAD(sbu_list);
+
+struct sbu {
+ char *uuid;
+ struct device_d *dev;
+ struct cdev *rcdev;
+ struct cdev cdev;
+ struct list_head list;
+};
+
+void storage_by_uuid_check_exist(struct cdev *cdev);
+
+static ssize_t sbu_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_read(sbu->rcdev, buf, count, offset, flags);
+}
+
+static ssize_t sbu_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_write(sbu->rcdev, buf, count, offset, flags);
+}
+
+static int sbu_ioctl(struct cdev *cdev, int request, void *buf)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_ioctl(sbu->rcdev, request, buf);
+}
+
+static int sbu_open(struct cdev *cdev, unsigned long flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_open(sbu->rcdev, flags);
+}
+
+static int sbu_close(struct cdev *cdev)
+{
+ struct sbu *sbu = cdev->priv;
+
+ cdev_close(sbu->rcdev);
+
+ return 0;
+}
+
+static int sbu_flush(struct cdev *cdev)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_flush(sbu->rcdev);
+}
+
+static int sbu_erase(struct cdev *cdev, loff_t count, loff_t offset)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_erase(sbu->rcdev, count, offset);
+}
+
+static int sbu_protect(struct cdev *cdev, size_t count, loff_t offset, int prot)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_protect(sbu->rcdev, count, offset, prot);
+}
+
+static int sbu_discard_range(struct cdev *cdev, loff_t count, loff_t offset)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_discard_range(sbu->rcdev, count, offset);
+}
+
+static int sbu_memmap(struct cdev *cdev, void **map, int flags)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_memmap(sbu->rcdev, map, flags);
+}
+
+static int sbu_truncate(struct cdev *cdev, size_t size)
+{
+ struct sbu *sbu = cdev->priv;
+
+ return cdev_truncate(sbu->rcdev, size);
+}
+
+static struct cdev_operations sbu_ops = {
+ .read = sbu_read,
+ .write = sbu_write,
+ .ioctl = sbu_ioctl,
+ .open = sbu_open,
+ .close = sbu_close,
+ .flush = sbu_flush,
+ .erase = sbu_erase,
+ .protect = sbu_protect,
+ .discard_range = sbu_discard_range,
+ .memmap = sbu_memmap,
+ .truncate = sbu_truncate,
+};
+
+static void storage_by_uuid_add_partitions(struct sbu *sbu, struct cdev *rcdev)
+{
+ int ret;
+
+ if (sbu->rcdev)
+ return;
+
+ sbu->rcdev = rcdev;
+ sbu->cdev.name = sbu->uuid;
+ sbu->cdev.size = rcdev->size;
+ sbu->cdev.ops = &sbu_ops;
+ sbu->cdev.dev = sbu->dev;
+ sbu->cdev.priv = sbu;
+
+ ret = devfs_create(&sbu->cdev);
+ if (ret) {
+ dev_err(sbu->dev, "Failed to create cdev: %s\n", strerror(-ret));
+ return;
+ }
+
+ of_parse_partitions(&sbu->cdev, sbu->dev->device_node);
+}
+
+static void check_exist(struct sbu *sbu)
+{
+ struct cdev *cdev;
+
+ for_each_cdev(cdev) {
+ if (!strcmp(cdev->uuid, sbu->uuid)) {
+ dev_dbg(sbu->dev, "Found %s %s\n", cdev->name, cdev->uuid);
+ storage_by_uuid_add_partitions(sbu, cdev);
+ }
+ }
+}
+
+static int sbu_detect(struct device_d *dev)
+{
+ struct sbu *sbu = dev->priv;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ check_exist(sbu);
+
+ return 0;
+}
+
+static int storage_by_uuid_probe(struct device_d *dev)
+{
+ struct sbu *sbu;
+ int ret;
+ const char *uuid;
+
+ sbu = xzalloc(sizeof(*sbu));
+
+ ret = of_property_read_string(dev->device_node, "uuid", &uuid);
+ if (ret)
+ return ret;
+
+ sbu->dev = dev;
+ sbu->uuid = xstrdup(uuid);
+
+ list_add_tail(&sbu->list, &sbu_list);
+
+ check_exist(sbu);
+ dev->priv = sbu;
+ dev->detect = sbu_detect;
+
+ return 0;
+}
+
+static struct of_device_id storage_by_uuid_dt_ids[] = {
+ {
+ .compatible = "barebox,storage-by-uuid",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d storage_by_uuid_driver = {
+ .name = "storage-by-uuid",
+ .probe = storage_by_uuid_probe,
+ .of_compatible = storage_by_uuid_dt_ids,
+};
+device_platform_driver(storage_by_uuid_driver);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 80465d6d50..2591610c3f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2383,7 +2383,7 @@ static void of_platform_device_create_root(struct device_node *np)
ret = platform_device_register(dev);
if (ret)
- free(dev);
+ free_device(dev);
}
static const struct of_device_id reserved_mem_matches[] = {
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 3a82809cb3..0e718469db 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -155,7 +155,7 @@ struct device_d *of_platform_device_create(struct device_node *np,
np->dev = NULL;
- free(dev);
+ free_device(dev);
if (num_reg)
free(res);
return NULL;
@@ -278,6 +278,7 @@ static struct device_d *of_amba_device_create(struct device_node *np)
return &dev->dev;
amba_err_free:
+ free_device_res(&dev->dev);
free(dev);
return NULL;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4eede13a11..34a0f004f7 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -534,6 +534,7 @@ void usb_free_device(struct usb_device *usbdev)
{
dma_free(usbdev->descriptor);
dma_free(usbdev->setup_packet);
+ free_device_res(&usbdev->dev);
free(usbdev);
}