[PATCH v5 12/13] gunyah: rsc_mgr: Add subdevices bus

Elliot Berman
2022-10-11T00:10:58Z

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

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