@@ -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
@@ -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");
@@ -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
new file mode 100644
@@ -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);
@@ -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
@@ -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 */
@@ -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;
}
@@ -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.
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@quicinc.com> --- 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