[v6,11/21] gunyah: rsc_mgr: Add subdevices bus

Message ID 20221026185846.3983888-12-quic_eberman@quicinc.com
State New
Headers
Series Drivers for gunyah hypervisor |

Commit Message

Elliot Berman Oct. 26, 2022, 6:58 p.m. UTC
  Gunyah Resource Manager exposes an interface which should occupy a few
devices on Linux:
 - a remote procedure call framework to talk to RM
 - 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     | 42 ++++++++++++++--
 drivers/virt/gunyah/rsc_mgr.h     | 10 ++++
 drivers/virt/gunyah/rsc_mgr_bus.c | 83 +++++++++++++++++++++++++++++++
 include/linux/gunyah_rsc_mgr.h    | 19 +++++++
 include/linux/mod_devicetable.h   |  8 +++
 scripts/mod/devicetable-offsets.c |  3 ++
 scripts/mod/file2alias.c          | 10 ++++
 8 files changed, 173 insertions(+), 4 deletions(-)
 create mode 100644 drivers/virt/gunyah/rsc_mgr_bus.c
  

Patch

diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile
index 2c18b0a56413..a9169af6c61f 100644
--- a/drivers/virt/gunyah/Makefile
+++ b/drivers/virt/gunyah/Makefile
@@ -1,4 +1,4 @@ 
 obj-$(CONFIG_GUNYAH) += gunyah.o
 
-gunyah_rsc_mgr-y += rsc_mgr.o
+gunyah_rsc_mgr-y += rsc_mgr.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 a9fde703cbbe..f2f776edecb8 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 vm_mgr_dev;
 };
 
 static struct gh_rsc_mgr *__rsc_mgr;
@@ -567,17 +569,27 @@  static int gh_rm_drv_probe(struct platform_device *pdev)
 
 	__rsc_mgr = rsc_mgr;
 
+	ret = gh_rm_device_add(&rsc_mgr->vm_mgr_dev, &pdev->dev, GH_RM_DEVICE_VM_MGR);
+	if (ret)
+		goto err_msgq;
+
 	return 0;
+
+err_msgq:
+	gh_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);
+
 	__rsc_mgr = NULL;
 
-	mbox_free_channel(gunyah_msgq_chan(&rsc_mgr->msgq));
-	gunyah_msgq_remove(&rsc_mgr->msgq);
+	mbox_free_channel(gh_msgq_chan(&rsc_mgr->msgq));
+	gh_msgq_remove(&rsc_mgr->msgq);
 
 	return 0;
 }
@@ -596,7 +608,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 e4f2499267bf..129e9d514f2a 100644
--- a/drivers/virt/gunyah/rsc_mgr.h
+++ b/drivers/virt/gunyah/rsc_mgr.h
@@ -31,4 +31,14 @@ 
 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..bbb3bdc747cc
--- /dev/null
+++ b/drivers/virt/gunyah/rsc_mgr_bus.c
@@ -0,0 +1,83 @@ 
+// 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);
+
+	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 b3b37225b7fb..0eeb7202fa33 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
 
@@ -23,4 +25,21 @@  struct gh_rm_notification {
 int gh_rm_register_notifier(struct notifier_block *nb);
 int gh_rm_unregister_notifier(struct notifier_block *nb);
 
+#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.