diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2022-02-18 12:59:21 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2022-02-18 12:59:21 +0100 |
commit | 9481ada6ad354cfe38418354afee48ceca438c05 (patch) | |
tree | e030cda328c36643b1c5085c9be7c5f2210f579b /drivers | |
parent | a32d0e18fb1bc738ae1aa79d8713b178c977988c (diff) | |
parent | eedf7a3b5f990dff893b54740ceea917c24e2cb7 (diff) | |
download | barebox-9481ada6ad354cfe38418354afee48ceca438c05.tar.gz barebox-9481ada6ad354cfe38418354afee48ceca438c05.tar.xz |
Merge branch 'for-next/efi'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/driver.c | 30 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 23 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/storage-by-uuid.c | 199 | ||||
-rw-r--r-- | drivers/of/base.c | 2 | ||||
-rw-r--r-- | drivers/of/platform.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 1 |
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); } |