[PATCH v2 06/11] virt: gunyah: Add capabilities bus and devices

Dmitry Baryshkov dmitry.baryshkov at linaro.org
Tue Aug 2 01:20:45 PDT 2022


On 02/08/2022 00:12, Elliot Berman wrote:
> Some resources provided by the Gunyah hypervisor are described as
> objects. The objects are identified with a capability ID. For instance,
> Inter-VM communication is performed with doorbells and message queues.
> Each doorbell and message queue endpoint can be described consisely as a
> Linux device.
> 
> These resources are discovered either on the devicetree or reported by
> the Resource Manager. Devices on the Gunyah bus are matched with drivers
> according to the type ID reported by resource manager. Most resources
> will be discovered directly from the resource manager, so matching
> directly on type ID seems like sensible design.
> 
> Each resource may also optionally have an interrupt associated with it
> and a known partner VM (e.g. which VM is the receiver of a message
> queue).
> 
> Signed-off-by: Elliot Berman <quic_eberman at quicinc.com>
> ---
>   drivers/virt/gunyah/Makefile         |   2 +-
>   drivers/virt/gunyah/device.c         | 108 +++++++++++++++++++++++++++
>   drivers/virt/gunyah/gunyah_private.h |  12 +++
>   drivers/virt/gunyah/sysfs.c          |  25 ++++++-
>   include/linux/gunyah.h               |  45 +++++++++++
>   5 files changed, 189 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/virt/gunyah/device.c
>   create mode 100644 drivers/virt/gunyah/gunyah_private.h
> 
> diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile
> index 0aa086f9149f..3869fb7371df 100644
> --- a/drivers/virt/gunyah/Makefile
> +++ b/drivers/virt/gunyah/Makefile
> @@ -1,4 +1,4 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   
> -gunyah-y += sysfs.o
> +gunyah-y += sysfs.o device.o
>   obj-$(CONFIG_GUNYAH) += gunyah.o
> \ No newline at end of file

Even git-format-patch warns you that should be a newline at the end of 
the file.

> diff --git a/drivers/virt/gunyah/device.c b/drivers/virt/gunyah/device.c
> new file mode 100644
> index 000000000000..93595f9a65b9
> --- /dev/null
> +++ b/drivers/virt/gunyah/device.c
> @@ -0,0 +1,108 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#define pr_fmt(fmt) "ghdev: " fmt
> +
> +#include <linux/interrupt.h>
> +#include <linux/gunyah.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +
> +#include "gunyah_private.h"
> +
> +static int gunyah_match(struct device *dev, struct device_driver *drv)
> +{
> +	struct gunyah_device *ghdev = to_gunyah_device(dev);
> +	struct gunyah_driver *ghdrv = to_gunyah_driver(drv);
> +
> +	return ghdev->type == ghdrv->type;
> +}
> +
> +static int gunyah_probe(struct device *dev)
> +{
> +	struct gunyah_device *ghdev = to_gunyah_device(dev);
> +	struct gunyah_driver *ghdrv = to_gunyah_driver(dev->driver);
> +
> +	return ghdrv->probe ? ghdrv->probe(ghdev) : 0;
> +}
> +
> +static void gunyah_remove(struct device *dev)
> +{
> +	struct gunyah_device *ghdev = to_gunyah_device(dev);
> +	struct gunyah_driver *ghdrv = to_gunyah_driver(dev->driver);
> +
> +	if (ghdrv->remove)
> +		ghdrv->remove(ghdev);
> +}
> +
> +static struct bus_type gunyah_bus = {
> +	.name	= "gunyah",
> +	.match	= gunyah_match,
> +	.probe	= gunyah_probe,
> +	.remove	= gunyah_remove,
> +};
> +
> +int gunyah_register_driver(struct gunyah_driver *ghdrv)
> +{
> +	ghdrv->driver.bus = &gunyah_bus;
> +	return driver_register(&ghdrv->driver);
> +}
> +
> +void gunyah_unregister_driver(struct gunyah_driver *ghdrv)
> +{
> +	driver_unregister(&ghdrv->driver);
> +}
> +
> +static void gunyah_device_release(struct device *dev)
> +{
> +	struct gunyah_device *ghdev = to_gunyah_device(dev);
> +
> +	kfree(ghdev);
> +}
> +
> +struct gunyah_device *gunyah_device_alloc(struct device *parent, gh_capid_t capid, u8 type)
> +{
> +	struct gunyah_device *ghdev;
> +
> +	ghdev = kzalloc(sizeof(*ghdev), GFP_KERNEL);
> +	if (!ghdev)
> +		return NULL;
> +
> +	ghdev->capid = capid;
> +	ghdev->type = type;
> +	ghdev->irq = IRQ_NOTCONNECTED;
> +	ghdev->dev.parent = parent;
> +	ghdev->dev.release = gunyah_device_release;
> +	ghdev->dev.bus = &gunyah_bus;
> +	device_initialize(&ghdev->dev);
> +	return ghdev;
> +}
> +
> +int gunyah_device_add(struct gunyah_device *ghdev)
> +{
> +	int ret;
> +
> +	ret = dev_set_name(&ghdev->dev, "%u.%08llx", ghdev->type, ghdev->capid);
> +	if (ret)
> +		return ret;
> +
> +	return device_add(&ghdev->dev);
> +}

Does your device need any additional setup between _alloc() and _add(). 
  If not, it may be better to squash them together.

> +
> +void gunyah_device_remove(struct gunyah_device *ghdev)
> +{
> +	device_unregister(&ghdev->dev);
> +}
> +
> +int __init gunyah_bus_init(void)
> +{
> +	return bus_register(&gunyah_bus);
> +}
> +
> +void gunyah_bus_exit(void)
> +{
> +	bus_unregister(&gunyah_bus);
> +}
> diff --git a/drivers/virt/gunyah/gunyah_private.h b/drivers/virt/gunyah/gunyah_private.h
> new file mode 100644
> index 000000000000..5f3832608020
> --- /dev/null
> +++ b/drivers/virt/gunyah/gunyah_private.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _GUNYAH_PRIVATE_H
> +#define _GUNYAH_PRIVATE_H
> +
> +int __init gunyah_bus_init(void);
> +void gunyah_bus_exit(void);
> +
> +#endif
> diff --git a/drivers/virt/gunyah/sysfs.c b/drivers/virt/gunyah/sysfs.c
> index 253433a939cf..220560cb3b1c 100644
> --- a/drivers/virt/gunyah/sysfs.c
> +++ b/drivers/virt/gunyah/sysfs.c
> @@ -12,6 +12,8 @@
>   #include <linux/init.h>
>   #include <linux/of.h>
>   
> +#include "gunyah_private.h"
> +
>   #define QC_HYP_UID0 0x19bd54bd
>   #define QC_HYP_UID1 0x0b37571b
>   #define QC_HYP_UID2 0x946f609b
> @@ -67,7 +69,13 @@ static struct kobj_attribute variant_attr = __ATTR_RO(variant);
>   
>   static ssize_t features_show(struct kobject *kobj, struct kobj_attribute *attr, char *buffer)
>   {
> -	return sysfs_emit(buffer, "\n");
> +	int len = 0;
> +
> +	if (GH_IDENTIFY_PARTITION_CSPACE(gunyah_api.flags))
> +		len += sysfs_emit_at(buffer, len, "cspace ");

How is this related to Linux gunyah bus implementation? Please move to 
the sysfs patch.

> +
> +	len += sysfs_emit_at(buffer, len, "\n");
> +	return len;
>   }
>   static struct kobj_attribute features_attr = __ATTR_RO(features);
>   
> @@ -105,6 +113,7 @@ static void gh_sysfs_unregister(void)
>   
>   static int __init gunyah_init(void)
>   {
> +	int ret;
>   	unsigned long uid[4];
>   
>   	arch_gh_hypercall(GH_HYPERCALL_CALL_UID, 0, uid[0], uid[1], uid[2], uid[3]);
> @@ -125,12 +134,24 @@ static int __init gunyah_init(void)
>   		  GH_API_INFO_API_VERSION(gunyah_api.api_info),
>   		  GH_API_INFO_VARIANT(gunyah_api.api_info));
>   
> -	return gh_sysfs_register();
> +	ret = gh_sysfs_register();
> +	if (ret)
> +		return ret;
> +
> +	ret = gunyah_bus_init();
> +	if (ret)
> +		goto err_sysfs;
> +
> +	return ret;
> +err_sysfs:
> +	gh_sysfs_unregister();
> +	return ret;
>   }
>   module_init(gunyah_init);
>   
>   static void __exit gunyah_exit(void)
>   {
> +	gunyah_bus_exit();
>   	gh_sysfs_unregister();
>   }
>   module_exit(gunyah_exit);
> diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
> index 69931a0f5736..ce35f4491773 100644
> --- a/include/linux/gunyah.h
> +++ b/include/linux/gunyah.h
> @@ -6,6 +6,7 @@
>   #ifndef _GUNYAH_H
>   #define _GUNYAH_H
>   
> +#include <linux/device.h>
>   #include <linux/types.h>
>   #include <linux/errno.h>
>   #include <asm/gunyah.h>
> @@ -72,4 +73,48 @@ static inline int gh_remap_error(int gh_error)
>   	}
>   }
>   
> +/* Follows resource manager's resource types for VM_GET_HYP_RESOURCES */
> +#define GUNYAH_DEVICE_TYPE_BELL_TX	0
> +#define GUNYAH_DEVICE_TYPE_BELL_RX	1
> +#define GUNYAH_DEVICE_TYPE_MSGQ_TX	2
> +#define GUNYAH_DEVICE_TYPE_MSGQ_RX	3
> +#define GUNYAH_DEVICE_TYPE_VCPU		4
> +
> +struct gunyah_device {
> +	u8 type;
> +	gh_capid_t capid;
> +	int irq;
> +
> +	struct device dev;
> +};
> +
> +#define to_gunyah_device(dev) container_of(dev, struct gunyah_device, dev)
> +
> +static inline void *ghdev_get_drvdata(const struct gunyah_device *ghdev)
> +{
> +	return dev_get_drvdata(&ghdev->dev);
> +}
> +
> +static inline void ghdev_set_drvdata(struct gunyah_device *ghdev, void *data)
> +{
> +	dev_set_drvdata(&ghdev->dev, data);
> +}
> +
> +struct gunyah_device *gunyah_device_alloc(struct device *parent, gh_capid_t capid, u8 type);
> +
> +int gunyah_device_add(struct gunyah_device *ghdev);
> +void gunyah_device_remove(struct gunyah_device *ghdev);
> +
> +struct gunyah_driver {
> +	struct device_driver driver;
> +	u8 type;
> +	int (*probe)(struct gunyah_device *ghdev);
> +	int (*remove)(struct gunyah_device *ghdev);
> +};
> +
> +#define to_gunyah_driver(drv) container_of(drv, struct gunyah_driver, driver)
> +
> +int gunyah_register_driver(struct gunyah_driver *ghdrv);
> +void gunyah_unregister_driver(struct gunyah_driver *ghdrv);
> +
>   #endif


-- 
With best wishes
Dmitry



More information about the linux-arm-kernel mailing list