Gunyah Resource Manager exposes an interface which should occupy a few devices on Linux: - a remote procedure call framework to talk to RM - a console device for VMs to interact with each other - a virtual machine manager to launch VMs, share memory with them, schedule runtime for those VMs, and handle certain faults. Create a virtual device bus for the console and VM Manager functions. Signed-off-by: Elliot Berman <quic_eberman@xxxxxxxxxxx> --- drivers/virt/gunyah/Makefile | 2 +- drivers/virt/gunyah/rsc_mgr.c | 45 ++++++++++++++++- drivers/virt/gunyah/rsc_mgr.h | 10 ++++ drivers/virt/gunyah/rsc_mgr_bus.c | 84 +++++++++++++++++++++++++++++++ include/linux/gunyah_rsc_mgr.h | 20 ++++++++ include/linux/mod_devicetable.h | 8 +++ scripts/mod/devicetable-offsets.c | 3 ++ scripts/mod/file2alias.c | 10 ++++ 8 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 drivers/virt/gunyah/rsc_mgr_bus.c diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile index 5eb6ad3c45ba..c376f403e712 100644 --- a/drivers/virt/gunyah/Makefile +++ b/drivers/virt/gunyah/Makefile @@ -1,5 +1,5 @@ gunyah-y += gunyah.o obj-$(CONFIG_GUNYAH) += gunyah.o -gunyah_rsc_mgr-y += rsc_mgr.o rsc_mgr_rpc.o +gunyah_rsc_mgr-y += rsc_mgr.o rsc_mgr_rpc.o rsc_mgr_bus.o obj-$(CONFIG_GUNYAH_RESORUCE_MANAGER) += gunyah_rsc_mgr.o diff --git a/drivers/virt/gunyah/rsc_mgr.c b/drivers/virt/gunyah/rsc_mgr.c index 0e2f04984ada..cdf96cb29c23 100644 --- a/drivers/virt/gunyah/rsc_mgr.c +++ b/drivers/virt/gunyah/rsc_mgr.c @@ -98,6 +98,8 @@ struct gh_rsc_mgr { struct mutex send_lock; struct work_struct recv_work; + + struct gh_rm_device console_dev, vm_mgr_dev; }; static struct gh_rsc_mgr *__rsc_mgr; @@ -566,13 +568,30 @@ static int gh_rm_drv_probe(struct platform_device *pdev) __rsc_mgr = rsc_mgr; + ret = gh_rm_device_add(&rsc_mgr->console_dev, &pdev->dev, GH_RM_DEVICE_CONSOLE); + if (ret) + goto err_msgq; + + ret = gh_rm_device_add(&rsc_mgr->vm_mgr_dev, &pdev->dev, GH_RM_DEVICE_VM_MGR); + if (ret) + goto err_console_remove; + return 0; + +err_console_remove: + gh_rm_device_delete(&rsc_mgr->console_dev); +err_msgq: + gunyah_msgq_remove(&rsc_mgr->msgq); + return ret; } static int gh_rm_drv_remove(struct platform_device *pdev) { struct gh_rsc_mgr *rsc_mgr = platform_get_drvdata(pdev); + gh_rm_device_delete(&rsc_mgr->vm_mgr_dev); + gh_rm_device_delete(&rsc_mgr->console_dev); + __rsc_mgr = NULL; mbox_free_channel(gunyah_msgq_chan(&rsc_mgr->msgq)); @@ -595,7 +614,31 @@ static struct platform_driver gh_rm_driver = { .of_match_table = gh_rm_of_match, }, }; -module_platform_driver(gh_rsc_mgr_driver); + +static int __init gh_rm_init(void) +{ + int ret; + + ret = gh_rm_bus_register(); + if (ret) { + pr_err("Failed to register gh_rm_bus: %d\n", ret); + return ret; + } + + ret = platform_driver_register(&gh_rm_driver); + if (ret) + gh_rm_bus_unregister(); + + return ret; +} +subsys_initcall(gh_rm_init); + +static void __exit gh_rm_exit(void) +{ + platform_driver_unregister(&gh_rm_driver); + gh_rm_bus_unregister(); +} +module_exit(gh_rm_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Gunyah Resource Manager Driver"); diff --git a/drivers/virt/gunyah/rsc_mgr.h b/drivers/virt/gunyah/rsc_mgr.h index 4620ac648bcf..a511858a456d 100644 --- a/drivers/virt/gunyah/rsc_mgr.h +++ b/drivers/virt/gunyah/rsc_mgr.h @@ -53,4 +53,14 @@ struct gh_vm_console_write_req { int gh_rm_call(u32 message_id, void *req_buff, size_t req_buff_size, void **resp_buf, size_t *resp_buff_size); +struct gh_rm_device { + struct device dev; + const char *name; +}; + +int gh_rm_bus_register(void); +void gh_rm_bus_unregister(void); +int gh_rm_device_add(struct gh_rm_device *ghrm_dev, struct device *parent, const char *name); +void gh_rm_device_delete(struct gh_rm_device *ghrm_dev); + #endif diff --git a/drivers/virt/gunyah/rsc_mgr_bus.c b/drivers/virt/gunyah/rsc_mgr_bus.c new file mode 100644 index 000000000000..dfd466c775f4 --- /dev/null +++ b/drivers/virt/gunyah/rsc_mgr_bus.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) "gh_rsc_mgr: " fmt + +#include <linux/device.h> +#include <linux/gunyah_rsc_mgr.h> +#include <linux/mod_devicetable.h> + +#include "rsc_mgr.h" + +#define to_gh_rm_device(dev) container_of(dev, struct gh_rm_device, dev) +#define to_gh_rm_driver(drv) container_of(drv, struct gh_rm_driver, drv) + +static int gh_rm_bus_match(struct device *dev, struct device_driver *drv) +{ + struct gh_rm_device *ghrm_dev = to_gh_rm_device(dev); + struct gh_rm_driver *ghrm_drv = to_gh_rm_driver(drv); + + // Multiple id_table entries not needed + return !strncmp(ghrm_dev->name, ghrm_drv->id_table->name, GUNYAH_RSC_MGR_NAME_SIZE); +} + +static int gh_rm_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct gh_rm_device *ghrm_dev = to_gh_rm_device(dev); + + return add_uevent_var(env, "MODALIAS=%s%s", GUNYAH_RSC_MGR_PREFIX, ghrm_dev->name); +} + +static struct bus_type gh_rm_bus = { + .name = "gh_rsc_mgr", + .match = gh_rm_bus_match, + .uevent = gh_rm_bus_uevent, +}; + +int gh_rm_bus_register(void) +{ + return bus_register(&gh_rm_bus); +} + +void gh_rm_bus_unregister(void) +{ + bus_unregister(&gh_rm_bus); +} + +int gh_rm_device_add(struct gh_rm_device *ghrm_dev, struct device *parent, const char *name) +{ + ghrm_dev->dev.bus = &gh_rm_bus; + ghrm_dev->dev.parent = parent; + ghrm_dev->name = name; + + device_initialize(&ghrm_dev->dev); + + dev_set_name(&ghrm_dev->dev, "%s.%s", dev_name(parent), name); + return device_add(&ghrm_dev->dev); +} + +void gh_rm_device_delete(struct gh_rm_device *ghrm_dev) +{ + device_del(&ghrm_dev->dev); +} + +int __gh_rm_driver_register(struct gh_rm_driver *ghrm_drv, struct module *owner, + const char *modname) +{ + if (WARN_ON(!ghrm_drv->drv.probe) || WARN_ON(!ghrm_drv->id_table)) + return -EINVAL; + + ghrm_drv->drv.bus = &gh_rm_bus; + ghrm_drv->drv.owner = owner; + ghrm_drv->drv.mod_name = modname; + + return driver_register(&ghrm_drv->drv); +} +EXPORT_SYMBOL_GPL(__gh_rm_driver_register); + +void gh_rm_driver_unregister(struct gh_rm_driver *ghrm_drv) +{ + driver_unregister(&ghrm_drv->drv); +} +EXPORT_SYMBOL_GPL(gh_rm_driver_unregister); diff --git a/include/linux/gunyah_rsc_mgr.h b/include/linux/gunyah_rsc_mgr.h index 2a1a51299247..7aea3344d655 100644 --- a/include/linux/gunyah_rsc_mgr.h +++ b/include/linux/gunyah_rsc_mgr.h @@ -9,6 +9,8 @@ #include <linux/list.h> #include <linux/notifier.h> #include <linux/gunyah.h> +#include <linux/device.h> +#include <linux/mod_devicetable.h> #define GH_VMID_INVAL U16_MAX @@ -41,4 +43,22 @@ int gh_rm_console_close(u16 vmid); int gh_rm_console_write(u16 vmid, const char *buf, size_t size); int gh_rm_console_flush(u16 vmid); +#define GH_RM_DEVICE_CONSOLE "console" +#define GH_RM_DEVICE_VM_MGR "vm_mgr" + +struct gh_rm_driver { + const struct gunyah_rsc_mgr_device_id *id_table; + struct device_driver drv; +}; + +int __gh_rm_driver_register(struct gh_rm_driver *ghrm_drv, struct module *owner, + const char *modname); +#define gh_rm_driver_register(ghrm_drv) \ + __gh_rm_driver_register(ghrm_drv, THIS_MODULE, KBUILD_MODNAME) + +void gh_rm_driver_unregister(struct gh_rm_driver *ghrm_drv); + +#define module_gh_rm_driver(ghrm_drv) \ + module_driver(ghrm_drv, gh_rm_driver_register, gh_rm_driver_unregister) + #endif diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 549590e9c644..c4dc0ee6ae00 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -911,4 +911,12 @@ struct ishtp_device_id { kernel_ulong_t driver_data; }; +#define GUNYAH_RSC_MGR_NAME_SIZE 32 +#define GUNYAH_RSC_MGR_PREFIX "gh_rsc_mgr:" + +struct gunyah_rsc_mgr_device_id { + const char name[GUNYAH_RSC_MGR_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index c0d3bcb99138..7b6944ed9336 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -262,5 +262,8 @@ int main(void) DEVID(ishtp_device_id); DEVID_FIELD(ishtp_device_id, guid); + DEVID(gunyah_rsc_mgr_device_id); + DEVID_FIELD(gunyah_rsc_mgr_device_id, name); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 80d973144fde..a02b9e8e02a8 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1452,6 +1452,15 @@ static int do_dfl_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: gh_rsc_mgr:S */ +static int do_gunyah_rsc_mgr_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD_ADDR(symval, gunyah_rsc_mgr_device_id, name); + sprintf(alias, GUNYAH_RSC_MGR_PREFIX "%s", *name); + + return 1; +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1531,6 +1540,7 @@ static const struct devtable devtable[] = { {"ssam", SIZE_ssam_device_id, do_ssam_entry}, {"dfl", SIZE_dfl_device_id, do_dfl_entry}, {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, + {"gh_rsc_mgr", SIZE_gunyah_rsc_mgr_device_id, do_gunyah_rsc_mgr_entry}, }; /* Create MODULE_ALIAS() statements. -- 2.25.1