Browse Source

msm-mmrm: add para virtualization backend

Add para virtualization backend.

Change-Id: Ifa25e422c04ef4dafb152130f303d0a217429c32
Signed-off-by: Mark Bao <[email protected]>
Mark Bao 3 năm trước cách đây
mục cha
commit
e84a7d930f

+ 16 - 0
Android.mk

@@ -45,3 +45,19 @@ LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
 # Include kp_module.ko in the /vendor/lib/modules (vendor.img)
 # BOARD_VENDOR_KERNEL_MODULES += $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE)
 include $(DLKM_DIR)/Build_external_kernelmodule.mk
+
+ifeq ($(CONFIG_MSM_MMRM_VM),y)
+	include $(CLEAR_VARS)
+	# For incremental compilation
+	LOCAL_SRC_FILES           := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*)
+	LOCAL_MODULE              := mmrm_vm_be.ko
+	LOCAL_MODULE_KBUILD_NAME  := vm/be/mmrm_vm_be.ko
+	LOCAL_MODULE_TAGS         := optional
+	LOCAL_MODULE_DEBUG_ENABLE := true
+	LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+	LOCAL_INIT_RC             := vm/be/src/mmrm_vm_be.rc
+	LOCAL_C_INCLUDES          := vm/common/inc/
+	# Include kp_module.ko in the /vendor/lib/modules (vendor.img)
+	# BOARD_VENDOR_KERNEL_MODULES += $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE)
+	include $(DLKM_DIR)/Build_external_kernelmodule.mk
+endif

+ 10 - 0
Kbuild

@@ -1,5 +1,15 @@
+
 include $(MMRM_ROOT)/config/waipiommrm.conf
 LINUXINCLUDE += -include $(MMRM_ROOT)/config/waipiommrmconf.h
 
+ifneq ($(CONFIG_ARCH_QTI_VM), y)
+
 obj-m += driver/
 obj-m += test/
+
+ifeq ($(CONFIG_MSM_MMRM_VM),y)
+LINUXINCLUDE += -I$(MMRM_ROOT)/vm/common/inc/
+obj-m += vm/be/
+endif
+
+endif

+ 1 - 0
config/waipiommrm.conf

@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 # Copyright (c) 2020, The Linux Foundation. All rights reserved.
 export CONFIG_MSM_MMRM=y
+export CONFIG_MSM_MMRM_VM=n

+ 13 - 0
driver/src/msm_mmrm.c

@@ -278,6 +278,19 @@ err_exit:
 }
 EXPORT_SYMBOL(mmrm_client_get_value);
 
+int mmrm_client_get_clk_count(void)
+{
+	struct mmrm_sw_clk_mgr_info *sinfo;
+
+	if (drv_data == (void *) -EPROBE_DEFER)
+		return 0;
+
+	sinfo = &(drv_data->clk_mgr->data.sw_info);
+
+	return sinfo->tot_clk_clients;
+}
+EXPORT_SYMBOL(mmrm_client_get_clk_count);
+
 static int sysfs_get_param(const char *buf, u32 *param)
 {
 	int base;

+ 9 - 0
vm/be/Kbuild

@@ -0,0 +1,9 @@
+ifeq ($(CONFIG_MSM_MMRM_VM),y)
+LINUXINCLUDE += -I$(MMRM_ROOT)/vm/be/src -I$(MMRM_ROOT)/driver/src
+
+obj-m += mmrm_vm_be.o
+mmrm_vm_be-objs := src/mmrm_vm_be_main.o \
+		src/mmrm_vm_be_dispatch.o \
+		src/mmrm_vm_be_msgq.o \
+		../cmn/src/mmrm_vm_debug.o
+endif

+ 32 - 0
vm/be/src/mmrm_vm_be.h

@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MMRM_VM_BE_H_
+#define _MMRM_VM_BE_H_
+
+#include <linux/soc/qcom/msm_mmrm.h>
+#include <mmrm_vm_interface.h>
+
+/*
+ * mmrm_vm_be_recv -- BE message receiving thread call this function
+ *                       for transfer receiving packet to BE
+ * @mmrm_vm: device driver info
+ * @data: message pointer
+ * @size: message size
+ */
+int mmrm_vm_be_recv(struct mmrm_vm_driver_data *mmrm_vm, void *data, size_t size);
+
+/*
+ * mmrm_vm_be_send_response -- BE message receiving thread call this function
+ *                             for sending back API calling result to FE
+ * @mmrm_vm: specific device driver info
+ * @size: message size
+ */
+int mmrm_vm_be_send_response(struct mmrm_vm_driver_data *mmrm_vm, void *msg);
+
+
+#endif /* _MMRM_VM_BE_H_ */
+
+

+ 9 - 0
vm/be/src/mmrm_vm_be.rc

@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+on boot
+	insmod /vendor/lib/modules/mmrm_vm_be.ko
+
+

+ 244 - 0
vm/be/src/mmrm_vm_be_dispatch.c

@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "mmrm_vm_debug.h"
+#include "mmrm_vm_interface.h"
+#include "mmrm_vm_msgq.h"
+#include "mmrm_vm_be.h"
+
+/**
+ * mmrm_vm_be_send_response - send response to FE
+ * mmrm_vm: driver private data
+ * msg: response message
+ */
+
+int mmrm_vm_be_send_response(struct mmrm_vm_driver_data *mmrm_vm, void *msg)
+{
+	struct mmrm_vm_response_msg_pkt *ppkt = (struct mmrm_vm_response_msg_pkt *)msg;
+	struct mmrm_vm_msg_hdr *hdr = &ppkt->hdr;
+	size_t msg_size = sizeof(*hdr) + hdr->size;
+	int rc;
+
+	hdr->version = MMRM_VM_VER_1;
+	hdr->type = MMRM_VM_TYPE_DATA;
+	hdr->flags = 0;
+
+	rc = mmrm_vm_msgq_send(mmrm_vm, msg, msg_size);
+	d_mpr_l("%s: size:%d rc=%d\n", __func__, msg_size, rc);
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_client_register - call mmrm API to register client
+ * mmrm_vm: driver private data
+ * req: request parameters
+ */
+static int mmrm_vm_be_client_register(struct mmrm_vm_driver_data *mmrm_vm,
+	struct mmrm_vm_api_request_msg *req)
+{
+	struct mmrm_client *pClient;
+	int rc;
+	struct mmrm_vm_response_msg_pkt pkt;
+	struct mmrm_client_desc client_desc;
+
+	// unpacketizing the call from fe on SVM
+	client_desc.client_type = req->data.reg.client_type;
+	memcpy(&(client_desc.client_info.desc), &(req->data.reg.desc),
+				sizeof(client_desc.client_info.desc));
+	client_desc.priority = req->data.reg.priority;
+
+	d_mpr_l("%s: register type:%d priority:%d\n", __func__,
+			client_desc.client_type, client_desc.priority);
+	d_mpr_l("%s: domain:%d client ID:%d\n", __func__,
+			client_desc.client_info.desc.client_domain,
+			client_desc.client_info.desc.client_id);
+	d_mpr_l("%s: clk name:%s\n", __func__, client_desc.client_info.desc.name);
+
+	// call mmrm register function
+	pClient = mmrm_client_register(&client_desc);
+	if (pClient != NULL) {
+		mmrm_vm->clk_client_tbl[pClient->client_uid] = pClient;
+		pkt.msg.data.reg.client_id = pClient->client_uid;
+	} else {
+		pkt.msg.data.reg.client_id = 0;
+		d_mpr_e("%s: client:%p\n", __func__, pClient);
+	}
+
+	// prepare response packet & send to fe on SVM
+	pkt.msg.hd.cmd_id = MMRM_VM_RESPONSE_REGISTER;
+	pkt.msg.hd.seq_no = req->hd.seq_no;
+	pkt.hdr.size = sizeof(pkt.msg.hd) + sizeof(pkt.msg.data.reg);
+
+	d_mpr_l("%s: cmd_id:%d data size:%d\n", __func__, pkt.msg.hd.cmd_id, pkt.hdr.size);
+
+	rc = mmrm_vm_be_send_response(mmrm_vm, &pkt);
+	if (rc != 0)
+		d_mpr_e("%s: rc:%d\n", __func__, rc);
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_client_setvalue - call mmrm API to set client values
+ * mmrm_vm: driver private data
+ * req: set client value request parameters
+ */
+static int mmrm_vm_be_client_setvalue(struct mmrm_vm_driver_data *mmrm_vm,
+	struct mmrm_vm_api_request_msg *req)
+{
+	struct mmrm_vm_response_msg_pkt pkt_resp;
+	int rc;
+	struct mmrm_vm_setvalue_request *req_param = &req->data.setval;
+
+	// call mmrm client set value function, and fill response packet
+
+	rc = mmrm_client_set_value(mmrm_vm->clk_client_tbl[req_param->client_id],
+			&req_param->data, req_param->val);
+
+	// prepare response packet & send to fe on SVM
+	pkt_resp.msg.hd.cmd_id = MMRM_VM_RESPONSE_SETVALUE;
+	pkt_resp.msg.hd.seq_no = req->hd.seq_no;
+	pkt_resp.hdr.size = sizeof(pkt_resp.msg.hd) + sizeof(pkt_resp.msg.data.setval);
+
+	pkt_resp.msg.data.setval.val = rc;
+
+	d_mpr_l("%s: cmd_id:%d data size:%d\n", __func__,
+		pkt_resp.msg.hd.cmd_id, pkt_resp.hdr.size);
+
+	rc = mmrm_vm_be_send_response(mmrm_vm, &pkt_resp);
+
+	if (rc != 0)
+		d_mpr_e("%s: rc:%d\n", __func__, rc);
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_client_setvalue_inrange - call mmrm API to set client range values
+ * mmrm_vm: driver private data
+ * req: set client value request parameters
+ */
+static int mmrm_vm_be_client_setvalue_inrange(struct mmrm_vm_driver_data *mmrm_vm,
+	struct mmrm_vm_api_request_msg *req)
+{
+	struct mmrm_vm_response_msg_pkt pkt;
+	int rc;
+	struct mmrm_vm_setvalue_inrange_request *req_param = &req->data.setval_range;
+
+	rc = mmrm_client_set_value_in_range(mmrm_vm->clk_client_tbl[req_param->client_id],
+		&req_param->data, &req_param->val);
+
+	pkt.msg.hd.cmd_id = MMRM_VM_RESPONSE_SETVALUE_INRANGE;
+	pkt.msg.hd.seq_no = req->hd.seq_no;
+	pkt.msg.data.setval_range.ret_code = rc;
+	pkt.hdr.size = sizeof(pkt.msg.hd) + sizeof(pkt.msg.data.setval_range);
+
+	d_mpr_l("%s: cmd_id:%d data size:%d\n", __func__, pkt.msg.hd.cmd_id, pkt.hdr.size);
+
+	rc = mmrm_vm_be_send_response(mmrm_vm, &pkt);
+	if (rc != 0)
+		d_mpr_e("%s: rc:%d\n", __func__, rc);
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_client_getvalue - call mmrm API to get client values
+ * mmrm_vm: driver private data
+ * req: set client value request parameters
+ */
+static int mmrm_vm_be_client_getvalue(struct mmrm_vm_driver_data *mmrm_vm,
+	struct mmrm_vm_api_request_msg *req)
+{
+	struct mmrm_vm_response_msg_pkt pkt;
+	int rc;
+	struct mmrm_vm_getvalue_request *req_param = &req->data.getval;
+	struct mmrm_client_res_value val;
+	struct mmrm_client_res_value *p_val = &pkt.msg.data.getval.val;
+
+	rc = mmrm_client_get_value(mmrm_vm->clk_client_tbl[req_param->client_id], &val);
+
+	pkt.msg.hd.cmd_id = MMRM_VM_RESPONSE_GETVALUE;
+	pkt.msg.hd.seq_no = req->hd.seq_no;
+	pkt.hdr.size = sizeof(pkt.msg.hd) + sizeof(pkt.msg.data.getval);
+
+	p_val->cur = val.cur;
+	p_val->max = val.max;
+	p_val->min = val.min;
+
+//	pr_err("%s: cmd_id:%d data size:%d\n", __func__, pkt.msg.hd.cmd_id, pkt.hdr.size);
+
+	rc = mmrm_vm_be_send_response(mmrm_vm, &pkt);
+	if (rc != 0)
+		d_mpr_e("%s: rc:%d\n", __func__, rc);
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_client_deregister - call mmrm API to deregister client
+ * mmrm_vm: driver private data
+ * req: set client value request parameters
+ */
+static int mmrm_vm_be_client_deregister(struct mmrm_vm_driver_data *mmrm_vm,
+		struct mmrm_vm_api_request_msg *req)
+{
+	int rc;
+	struct mmrm_vm_response_msg_pkt pkt;
+	struct mmrm_vm_deregister_request *req_param = &req->data.dereg;
+
+	rc = mmrm_client_deregister(mmrm_vm->clk_client_tbl[req_param->client_id]);
+//	pr_err("%s: client:%d\n", __func__, req_param->client_id);
+
+	pkt.msg.hd.cmd_id = MMRM_VM_RESPONSE_DEREGISTER;
+	pkt.msg.hd.seq_no = req->hd.seq_no;
+
+	pkt.hdr.size = sizeof(pkt.msg.hd) + sizeof(pkt.msg.data.dereg);
+	pkt.msg.data.dereg.ret_code = rc;
+
+//	pr_err("%s: cmd_id:%d data size:%d ret:%d\n", __func__,
+//		pkt.msg.hd.cmd_id, pkt.hdr.size, pkt.msg.data.dereg.ret_code);
+
+	rc = mmrm_vm_be_send_response(mmrm_vm, &pkt);
+	if (rc != 0)
+		d_mpr_e("%s: rc:%d\n", __func__, rc);
+	return rc;
+}
+
+
+/**
+ * mmrm_vm_be_recv - be dispatch mmrm request to mmrm API call
+ * mmrm_vm: driver private data
+ * data: request message buffer pointer
+ * size: request message size
+ */
+int mmrm_vm_be_recv(struct mmrm_vm_driver_data *mmrm_vm, void *data, size_t size)
+{
+	struct mmrm_vm_api_request_msg *cmd = data;
+	int rc = -1;
+
+	switch (cmd->hd.cmd_id) {
+	case MMRM_VM_REQUEST_REGISTER:
+		rc = mmrm_vm_be_client_register(mmrm_vm, cmd);
+		break;
+
+	case MMRM_VM_REQUEST_SETVALUE:
+		rc = mmrm_vm_be_client_setvalue(mmrm_vm, cmd);
+		break;
+
+	case MMRM_VM_REQUEST_SETVALUE_INRANGE:
+		rc = mmrm_vm_be_client_setvalue_inrange(mmrm_vm, cmd);
+		break;
+
+	case MMRM_VM_REQUEST_GETVALUE:
+		rc = mmrm_vm_be_client_getvalue(mmrm_vm, cmd);
+		break;
+
+	case MMRM_VM_REQUEST_DEREGISTER:
+		rc = mmrm_vm_be_client_deregister(mmrm_vm, cmd);
+		break;
+	default:
+		pr_err("%s: cmd_id:%d unknown!!!\n", __func__, cmd->hd.cmd_id);
+		break;
+	}
+	return rc;
+}
+

+ 115 - 0
vm/be/src/mmrm_vm_be_main.c

@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "mmrm_vm_be.h"
+#include "mmrm_vm_msgq.h"
+#include "mmrm_vm_interface.h"
+#include "mmrm_debug.h"
+
+#define MMRM_CLK_CLIENTS_NUM_MAX 35
+
+struct mmrm_vm_driver_data *drv_vm_be = (void *) -EPROBE_DEFER;
+
+int msm_mmrm_debug = MMRM_ERR | MMRM_WARN | MMRM_PRINTK;
+
+int mmrm_client_get_clk_count(void);
+
+static int mmrm_vm_be_driver_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int   sz, clk_count, rc;
+
+	drv_vm_be = devm_kzalloc(dev, sizeof(*drv_vm_be), GFP_KERNEL);
+	if (!drv_vm_be)
+		return -ENOMEM;
+
+	clk_count = mmrm_client_get_clk_count();
+	if (clk_count <= 0 || clk_count > MMRM_CLK_CLIENTS_NUM_MAX) {
+		d_mpr_e("%s: clk count is not correct\n", __func__);
+		goto clk_count_err;
+	}
+	sz = sizeof(struct mmrm_client *) * clk_count;
+	drv_vm_be->clk_client_tbl = devm_kzalloc(dev, sz, GFP_KERNEL);
+	if (!drv_vm_be->clk_client_tbl)
+		goto client_tbl_err;
+
+	drv_vm_be->debugfs_root = msm_mmrm_debugfs_init();
+	if (!drv_vm_be->debugfs_root)
+		d_mpr_e("%s: failed to create debugfs for mmrm\n", __func__);
+
+	dev_set_drvdata(&pdev->dev, drv_vm_be);
+	rc = mmrm_vm_msgq_init(drv_vm_be);
+	if (rc != 0) {
+		d_mpr_e("%s: failed to init msgq\n", __func__);
+		goto msgq_init_err;
+	}
+
+	dev_err(dev, "msgq probe success");
+	return 0;
+
+client_tbl_err:
+	dev_err(dev, "msgq register alloc memory failed");
+	return -ENOMEM;
+msgq_init_err:
+	kfree(drv_vm_be->clk_client_tbl);
+	msm_mmrm_debugfs_deinit(drv_vm_be->debugfs_root);
+	mmrm_vm_msgq_deinit(drv_vm_be);
+	dev_set_drvdata(&pdev->dev, NULL);
+clk_count_err:
+	kfree(drv_vm_be);
+	drv_vm_be = (void *) -EPROBE_DEFER;
+	return -EINVAL;
+}
+
+static int mmrm_vm_be_driver_remove(struct platform_device *pdev)
+{
+	mmrm_vm_msgq_deinit(drv_vm_be);
+	msm_mmrm_debugfs_deinit(drv_vm_be->debugfs_root);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(drv_vm_be);
+	drv_vm_be = (void *) -EPROBE_DEFER;
+	return 0;
+}
+
+static const struct of_device_id mmrm_vm_be_match[] = {
+	{ .compatible = "qcom,mmrm-vm-be" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mmrm_vm_be_match);
+
+static struct platform_driver mmrm_vm_be_driver = {
+	.probe = mmrm_vm_be_driver_probe,
+	.driver = {
+		.name = "mmrm-vm-be",
+		.of_match_table = mmrm_vm_be_match,
+	},
+	.remove = mmrm_vm_be_driver_remove,
+};
+
+static int __init mmrm_vm_be_module_init(void)
+{
+	pr_info("%s:  init start\n", __func__);
+
+	return platform_driver_register(&mmrm_vm_be_driver);
+}
+subsys_initcall(mmrm_vm_be_module_init);
+
+static void __exit mmrm_vm_be_module_exit(void)
+{
+	platform_driver_unregister(&mmrm_vm_be_driver);
+}
+module_exit(mmrm_vm_be_module_exit);
+
+MODULE_SOFTDEP("pre: gunyah_transport");
+MODULE_SOFTDEP("pre: msm-mmrm");
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MMRM BE Driver");
+MODULE_LICENSE("GPL v2");

+ 274 - 0
vm/be/src/mmrm_vm_be_msgq.c

@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/gunyah/gh_msgq.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/gunyah/gh_rm_drv.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+
+#include "mmrm_vm_be.h"
+#include "mmrm_vm_interface.h"
+#include "mmrm_vm_debug.h"
+
+#define MAX_ERR_COUNT 5
+
+/**
+ * mmrm_vm_msgq_msg_handler - fe request handler
+ * work: work parameter that workqueue thread transfer
+ */
+static void mmrm_vm_msgq_msg_handler(struct work_struct *work)
+{
+	struct mmrm_vm_thread_info *pthread_info =
+		container_of(work, struct mmrm_vm_thread_info, msgq_work.work);
+	struct mmrm_vm_driver_data *mmrm_vm =
+		container_of(pthread_info, struct mmrm_vm_driver_data, thread_info);
+	struct mmrm_vm_msg *msg;
+	struct mmrm_vm_msg *next_msg;
+	struct list_head   head;
+
+	if (IS_ERR_OR_NULL(work))
+		return;
+
+	mutex_lock(&pthread_info->list_lock);
+	list_replace_init(&pthread_info->queued_msg, &head);
+	mutex_unlock(&pthread_info->list_lock);
+
+	list_for_each_entry_safe(msg, next_msg, &head, link) {
+		mmrm_vm_be_recv(mmrm_vm, msg->msg_buf, msg->msg_size);
+		list_del(&msg->link);
+		kfree(msg);
+	}
+}
+
+/**
+ * mmrm_vm_be_msgq_listener - gunyah's message receiving thread
+ * data: parameter that caller transfer
+ */
+static int mmrm_vm_be_msgq_listener(void *data)
+{
+	struct mmrm_vm_driver_data *mmrm_vm;
+	struct mmrm_vm_gh_msgq_info *pmsg_info;
+	struct mmrm_vm_thread_info *thread_info;
+
+	struct mmrm_vm_msg *msg;
+	size_t size;
+	int ret = 0;
+	int err_count = 0;
+
+	if (IS_ERR_OR_NULL(data))
+		return -EINVAL;
+
+	mmrm_vm = (struct mmrm_vm_driver_data *)data;
+	pmsg_info = &mmrm_vm->msg_info;
+	thread_info = &mmrm_vm->thread_info;
+
+	while (true) {
+		msg = kzalloc(sizeof(struct mmrm_vm_msg), GFP_KERNEL);
+		if (!msg)
+			return -ENOMEM;
+
+		ret = gh_msgq_recv(pmsg_info->msgq_handle, msg->msg_buf,
+				GH_MSGQ_MAX_MSG_SIZE_BYTES, &size, 0);
+		if (ret < 0) {
+			kfree(msg);
+			d_mpr_e("gh_msgq_recv failed, rc=%d\n", ret);
+			err_count++;
+			if (err_count < MAX_ERR_COUNT)
+				continue;
+
+			return -EINVAL;
+		}
+
+		err_count = 0;
+		msg->msg_size = size;
+
+		mutex_lock(&thread_info->list_lock);
+		list_add_tail(&thread_info->queued_msg, &msg->link);
+		mutex_unlock(&thread_info->list_lock);
+
+		queue_delayed_work(thread_info->msg_workq,
+				 &thread_info->msgq_work, msecs_to_jiffies(0));
+	}
+
+	return 0;
+}
+
+/**
+ * mmrm_vm_msgq_send - send response message by gunyah API
+ * mmrm_vm: driver data
+ * msg: message buffer pointer
+ * msg_size: message size
+ */
+int mmrm_vm_msgq_send(struct mmrm_vm_driver_data *mmrm_vm, void *msg, size_t msg_size)
+{
+	if (!mmrm_vm->msg_info.msgq_handle) {
+		d_mpr_e("Failed to send msg, invalid msgq handle\n");
+		return -EINVAL;
+	}
+
+	if (msg_size > GH_MSGQ_MAX_MSG_SIZE_BYTES) {
+		d_mpr_e("msg size unsupported for msgq: %ld > %d\n", msg_size,
+				GH_MSGQ_MAX_MSG_SIZE_BYTES);
+		return -E2BIG;
+	}
+
+	return gh_msgq_send(mmrm_vm->msg_info.msgq_handle, msg, msg_size, GH_MSGQ_TX_PUSH);
+}
+
+/**
+ * mmrm_vm_be_gh_validate_register - check gunyah connection validation
+ * msg_info: gunyah meesage info
+ * vm_status_payload: gunyah notification message status info
+ */
+int mmrm_vm_be_gh_validate_register(struct mmrm_vm_gh_msgq_info *msg_info,
+		struct gh_rm_notif_vm_status_payload *vm_status_payload)
+{
+	gh_vmid_t peer_vmid;
+	gh_vmid_t self_vmid;
+	int rc = -1;
+
+	if (vm_status_payload->vm_status != GH_RM_VM_STATUS_READY)
+		return rc;
+
+	d_mpr_l("%s: status=%d\n", __func__, vm_status_payload->vm_status);
+	if (gh_rm_get_vmid(msg_info->peer_id, &peer_vmid))
+		return rc;
+
+	if (gh_rm_get_vmid(GH_PRIMARY_VM, &self_vmid))
+		return rc;
+
+	if (peer_vmid != vm_status_payload->vmid)
+		return NOTIFY_DONE;
+
+	d_mpr_l("%s: vmid=%d peer_vmid=%d\n", __func__, vm_status_payload->vmid, peer_vmid);
+
+	if (msg_info->msgq_handle) {
+		return rc;
+	}
+
+	msg_info->msgq_handle = gh_msgq_register(msg_info->msgq_label);
+
+	d_mpr_l("%s: label=%d\n", __func__, msg_info->msgq_label);
+	rc = 0;
+
+	if (IS_ERR_OR_NULL(msg_info->msgq_handle)) {
+		rc = -1;
+		d_mpr_e("%s: gunyah message queue registration failed\n", __func__);
+	}
+
+	return rc;
+}
+
+/**
+ * mmrm_vm_be_msgq_cb - check gunyah connection validation
+ * nb: gunyah notofier block info
+ * cmd: gunyah notification status category info
+ * data: user defined data pointer
+ */
+static int mmrm_vm_be_msgq_cb(struct notifier_block *nb, unsigned long cmd, void *data)
+{
+	struct gh_rm_notif_vm_status_payload *vm_status_payload;
+	struct mmrm_vm_driver_data *mmrm_vm;
+	struct mmrm_vm_gh_msgq_info *msg_info;
+	struct  mmrm_vm_thread_info *thread_info;
+	int rc;
+
+	if (IS_ERR_OR_NULL(nb))
+		return -EINVAL;
+
+	msg_info = container_of(nb, struct mmrm_vm_gh_msgq_info, pvt_nb);
+	mmrm_vm = container_of(msg_info, struct mmrm_vm_driver_data, msg_info);
+
+	thread_info = &mmrm_vm->thread_info;
+	if (cmd != GH_RM_NOTIF_VM_STATUS)
+		return NOTIFY_DONE;
+
+	/*
+	 * check VM status, only GH_TRUSTED_VM notification activate
+	 * GUNYAH message queue registering
+	 */
+	vm_status_payload = (struct gh_rm_notif_vm_status_payload *)data;
+	rc = mmrm_vm_be_gh_validate_register(msg_info, vm_status_payload);
+	if (rc != 0)
+		d_mpr_e("%s: msgq registration failed: err:%d\n",
+			__func__, PTR_ERR(msg_info->msgq_handle));
+
+	thread_info->msgq_listener_thread = kthread_run(mmrm_vm_be_msgq_listener,
+			(void *)mmrm_vm, "mmrm_msgq_listener");
+	if (IS_ERR_OR_NULL(thread_info->msgq_listener_thread)) {
+		return NOTIFY_DONE;
+	};
+
+	wake_up_process(thread_info->msgq_listener_thread);
+
+	return NOTIFY_DONE;
+}
+
+/**
+ * mmrm_vm_msgq_init - gunyah message queue initialization
+ * mmrm_vm: driver data
+ */
+int mmrm_vm_msgq_init(struct mmrm_vm_driver_data *mmrm_vm)
+{
+	struct mmrm_vm_gh_msgq_info *msg_info;
+	struct mmrm_vm_thread_info *thread_info;
+	int rc;
+
+	if (IS_ERR_OR_NULL(mmrm_vm))
+		return -EINVAL;
+
+	msg_info = &mmrm_vm->msg_info;
+	thread_info = &mmrm_vm->thread_info;
+
+	msg_info->msgq_label = GH_MSGQ_LABEL_MMRM;
+	d_mpr_l("%s:  msgq-label=%d\n", __func__, msg_info->msgq_label);
+
+	msg_info->peer_id = GH_TRUSTED_VM;
+	msg_info->pvt_nb.notifier_call = mmrm_vm_be_msgq_cb;
+	rc = gh_rm_register_notifier(&msg_info->pvt_nb);
+	if (rc != 0)
+		return -1;
+
+	mutex_init(&thread_info->list_lock);
+	INIT_LIST_HEAD(&thread_info->queued_msg);
+	thread_info->msg_workq = create_singlethread_workqueue("vm_message_workq");
+	if (IS_ERR_OR_NULL(thread_info->msg_workq)) {
+		return -1;
+	};
+	INIT_DELAYED_WORK(&thread_info->msgq_work, mmrm_vm_msgq_msg_handler);
+
+	return 0;
+}
+
+/**
+ * mmrm_vm_msgq_init - gunyah message queue de-initialization
+ * mmrm_vm: driver data
+ */
+int mmrm_vm_msgq_deinit(struct mmrm_vm_driver_data *mmrm_vm)
+{
+	struct mmrm_vm_gh_msgq_info *msg_info;
+	struct mmrm_vm_thread_info *thread_info;
+	int rc = 0;
+
+	if (IS_ERR_OR_NULL(mmrm_vm))
+		return -EINVAL;
+
+	msg_info = &mmrm_vm->msg_info;
+	thread_info = &mmrm_vm->thread_info;
+	if (thread_info->msgq_listener_thread)
+		kthread_stop(thread_info->msgq_listener_thread);
+
+	gh_rm_unregister_notifier(&msg_info->pvt_nb);
+
+	if (msg_info->msgq_handle) {
+		rc = gh_msgq_unregister(msg_info->msgq_handle);
+		if (rc != 0)
+			d_mpr_e("%s: msgq unregistration failed: err:%d\n", __func__, rc);
+	}
+	return rc;
+}

+ 63 - 0
vm/common/inc/mmrm_vm_debug.h

@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MMRM_VM_DEBUG__
+#define __MMRM_VM_DEBUG__
+
+#include <linux/debugfs.h>
+#include <linux/printk.h>
+
+#ifndef MMRM_VM_DBG_LABEL
+#define MMRM_VM_DBG_LABEL "mmrm_vm"
+#endif
+
+#define MMRM_VM_DBG_TAG MMRM_VM_DBG_LABEL ": %4s: "
+
+/* To enable messages OR these values and
+ * echo the result to debugfs file.
+ */
+enum mmrm_msg_prio {
+	MMRM_VM_ERR = 0x000001,
+	MMRM_VM_HIGH = 0x000002,
+	MMRM_VM_LOW = 0x000004,
+	MMRM_VM_WARN = 0x000008,
+	MMRM_VM_PRINTK = 0x010000,
+};
+
+extern int mmrm_vm_debug;
+
+#define dprintk(__level, __fmt, ...) \
+	do { \
+		if (mmrm_vm_debug & __level) { \
+			if (mmrm_vm_debug & MMRM_VM_PRINTK) { \
+				pr_info(MMRM_VM_DBG_TAG __fmt, \
+					get_debug_level_str(__level), \
+					##__VA_ARGS__); \
+			} \
+		} \
+	} while (0)
+
+#define d_mpr_e(__fmt, ...) dprintk(MMRM_VM_ERR, __fmt, ##__VA_ARGS__)
+#define d_mpr_h(__fmt, ...) dprintk(MMRM_VM_HIGH, __fmt, ##__VA_ARGS__)
+#define d_mpr_l(__fmt, ...) dprintk(MMRM_VM_LOW, __fmt, ##__VA_ARGS__)
+#define d_mpr_w(__fmt, ...) dprintk(MMRM_VM_WARN, __fmt, ##__VA_ARGS__)
+
+static inline char *get_debug_level_str(int level)
+{
+	switch (level) {
+	case MMRM_VM_ERR:
+		return "err ";
+	case MMRM_VM_HIGH:
+		return "high";
+	case MMRM_VM_LOW:
+		return "low ";
+	case MMRM_VM_WARN:
+		return "warn";
+	default:
+		return "????";
+	}
+}
+
+#endif /* __MMRM_VM_DEBUG__ */

+ 222 - 0
vm/common/inc/mmrm_vm_interface.h

@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MMRM_VM_INTERNAL_H__
+#define __MMRM_VM_INTERNAL_H__
+
+#include <linux/mutex.h>
+#include <linux/soc/qcom/msm_mmrm.h>
+
+#include <mmrm_vm_msgq.h>
+
+/**
+ * mmrm_vm_thread_info - message listener & workqueue info
+ * @msgq_listener_thread: handle to msgq listener thread that is used
+ *                        to receive/send messages through gunyah interface
+ * @msg_workq: message workqueue pointer
+ * @msgq_work: message work, worker thread to process the messages
+ * @queued_msg: message queue head
+ */
+struct mmrm_vm_thread_info {
+	struct task_struct *msgq_listener_thread;
+	struct workqueue_struct   *msg_workq;
+	struct delayed_work msgq_work;
+	struct mutex list_lock;
+	struct list_head   queued_msg;
+};
+
+/*
+ * struct mmrm_vm_data_priv -- device driver private part
+ * @msg_info: gunyah message info
+ * @thread_info: message lister & workqueue info
+ * @clk_client_tbl: index and client handler LUT
+ * @debugfs_root: debug fs, /sys/kernel/debug
+ * @vm_pvt_data: pointer to fe/be specific data
+ */
+struct mmrm_vm_driver_data {
+	struct mmrm_vm_gh_msgq_info msg_info;
+	struct mmrm_vm_thread_info thread_info;
+	struct mmrm_client **clk_client_tbl;
+
+	/* debugfs */
+	struct dentry *debugfs_root;
+	void *vm_pvt_data;
+};
+
+/*
+ * enum mmrm_vm_api_msg_id -- request/response cmd ID
+ */
+enum mmrm_vm_api_msg_id {
+	MMRM_VM_REQUEST_REGISTER = 1,
+	MMRM_VM_REQUEST_SETVALUE,
+	MMRM_VM_REQUEST_SETVALUE_INRANGE,
+	MMRM_VM_REQUEST_GETVALUE,
+	MMRM_VM_REQUEST_DEREGISTER,
+
+	MMRM_VM_RESPONSE_REGISTER = MMRM_VM_REQUEST_REGISTER | 0x800,
+	MMRM_VM_RESPONSE_SETVALUE,
+	MMRM_VM_RESPONSE_SETVALUE_INRANGE,
+	MMRM_VM_RESPONSE_GETVALUE,
+	MMRM_VM_RESPONSE_DEREGISTER,
+};
+
+/*
+ * struct msg_head -- message head
+ * @cmd_id: mmrm API message cmd id
+ * @seq_no: message sequence id
+ */
+struct mmrm_vm_api_msg_head {
+	enum mmrm_vm_api_msg_id cmd_id;
+	int  seq_no;
+};
+
+/*
+ * struct register_request -- mmrm register parameters
+ * @client_type: client type, definition see msm_mmrm.h
+ * @priority: client priority, definition see msm_mmrm.h
+ * @desc: client description, definition see msm_mmrm.h
+ */
+struct mmrm_vm_register_request {
+	enum mmrm_client_type client_type;
+	enum mmrm_client_priority priority;
+	struct mmrm_clk_client_desc desc;
+};
+
+/*
+ * struct deregister_request -- mmrm deregister parameters
+ * @client: client registered handle
+ */
+struct mmrm_vm_deregister_request {
+	u32 client_id;
+};
+
+/*
+ * struct setvalue_request -- mmrm setvalue parameters
+ * @client: client type, definition see msm_mmrm.h
+ * @data: client info, definition see msm_mmrm.h
+ * @val: new clock rate value
+ */
+struct mmrm_vm_setvalue_request {
+	u32 client_id;
+	struct mmrm_client_data data;
+	unsigned long val;
+};
+
+/*
+ * struct mmrm_vm_setvalue_inrange_request -- mmrm setvalue_inrange parameters
+ * @client: client type, definition see msm_mmrm.h
+ * @data: client info, definition see msm_mmrm.h
+ * @val: new clock rate value range, definition see msm_mmrm.h
+ */
+struct mmrm_vm_setvalue_inrange_request {
+	u32 client_id;
+	struct mmrm_client_data data;
+	struct mmrm_client_res_value val;
+};
+
+/*
+ * struct mmrm_vm_getvalue_request -- mmrm getvalue parameters
+ * @client: client type, definition see msm_mmrm.h
+ * @val: current clock rate value range, definition see msm_mmrm.h
+ */
+struct mmrm_vm_getvalue_request {
+	u32 client_id;
+};
+
+/*
+ * struct mmrm_vm_api_request_msg -- mmrm request API message unified data definition
+ * @hd: mmrm API request message head
+ * @data: parameters mmrm API needs per API message cmd id
+ */
+struct mmrm_vm_api_request_msg {
+	struct mmrm_vm_api_msg_head hd;
+	union {
+		struct mmrm_vm_register_request reg;
+		struct mmrm_vm_deregister_request dereg;
+		struct mmrm_vm_setvalue_request setval;
+		struct mmrm_vm_setvalue_inrange_request setval_range;
+		struct mmrm_vm_getvalue_request getval;
+	} data;
+};
+
+/*
+ * struct mmrm_vm_register_response -- mmrm_client_register API response message
+ * @client: handle for registered client
+ */
+struct mmrm_vm_register_response {
+	u32 client_id;
+};
+
+/*
+ * struct mmrm_vm_deregister_response -- mmrm_client_deregister API response message
+ * @ret_code: indicates if the mmrm_client_deregister is successful
+ */
+struct mmrm_vm_deregister_response {
+	int ret_code;
+};
+
+/*
+ * struct mmrm_vm_setvalue_response -- mmrm_client_set_value API response message
+ * @val: value that mmrm_client_set_value return
+ */
+struct mmrm_vm_setvalue_response {
+	unsigned long val;
+};
+
+/*
+ * struct mmrm_vm_setvalue_inrange_response -- mmrm_client_set_value_in_range API response message
+ * @ret_code: value that mmrm_client_set_value_in_range return
+ */
+struct mmrm_vm_setvalue_inrange_response {
+	int ret_code;
+};
+
+/*
+ * struct mmrm_vm_getvalue_response -- mmrm_client_get_value API response message
+ * @val: value that mmrm_client_get_value return
+ */
+struct mmrm_vm_getvalue_response {
+	struct mmrm_client_res_value val;
+};
+
+/*
+ * struct mmrm_vm_api_response_msg -- mmrm response message unified data
+ * @hd: mmrm API response message head
+ * @data: data that mmrm API return per API response message id
+ */
+struct mmrm_vm_api_response_msg {
+	struct mmrm_vm_api_msg_head hd;
+	union {
+		struct mmrm_vm_register_response reg;
+		struct mmrm_vm_deregister_response dereg;
+		struct mmrm_vm_setvalue_response setval;
+		struct mmrm_vm_setvalue_inrange_response setval_range;
+		struct mmrm_vm_getvalue_response getval;
+	} data;
+};
+
+/*
+ * struct mmrm_vm_request_msg_pkt -- mmrm request packet that is sent through gunyah API
+ * @hdr: message head for checking message valid
+ * @msg: data that is needed by mmrm API
+ */
+struct mmrm_vm_request_msg_pkt {
+	struct mmrm_vm_msg_hdr hdr;
+	struct mmrm_vm_api_request_msg msg;
+};
+
+/*
+ * struct mmrm_vm_response_msg_pkt -- mmrm response packet that is sent through gunyah API
+ * @hdr: message head for checking message valid
+ * @msg: data that is returned by mmrm API
+ */
+struct mmrm_vm_response_msg_pkt {
+	struct mmrm_vm_msg_hdr hdr;
+	struct mmrm_vm_api_response_msg msg;
+};
+
+#endif /* __MMRM_VM_INTERNAL_H__ */
+
+

+ 99 - 0
vm/common/inc/mmrm_vm_msgq.h

@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MMRM_VM_MSGQ_H__
+#define __MMRM_VM_MSGQ_H__
+
+#include <linux/gunyah/gh_msgq.h>
+
+#define MMRM_VM_VER_1 1       // mmrm version, for message valid check
+
+#define MMRM_VM_MAX_PKT_SZ  1024      // mmrm max gunyah packet size
+
+/* mmrm_vm_pkt_type: mmrm transfer type, for message valid check
+ * @MMRM_VM_TYPE_DATA: request/response data
+ */
+enum mmrm_vm_pkt_type {
+	MMRM_VM_TYPE_DATA = 1,
+};
+
+struct mmrm_vm_driver_data;
+
+/**
+ * struct mmrm_vm_msg_hdr - mmrm vm packet header
+ * @version: protocol version
+ * @type: packet type; one of MMRM_VM_TYPE_* in mmrm_vm_pkt_type
+ * @flags: Reserved for future use
+ * @size: length of packet, excluding this header
+ */
+struct mmrm_vm_msg_hdr {
+	u8 version;
+	u8 type;
+	u8 flags;
+	u8 resv;
+	u32 size;
+};
+
+/**
+ * mmrm_vm_msg - message that be received.
+ * @link - list head
+ * @msg_size - message size
+ * @msg_buf - message buffer
+ */
+struct mmrm_vm_msg {
+	struct list_head link;
+	size_t msg_size;
+	unsigned char msg_buf[GH_MSGQ_MAX_MSG_SIZE_BYTES];
+};
+
+/**
+ * mmrm_vm_msgq_info - gunyah info.
+ * @peer_id: notification callback check if message is from SVM
+ * @msgq_handle - registered msg queue handle with gunyah api
+ * @msgq_label - message queue label
+ * @pvt_nb - notifier info
+ */
+struct mmrm_vm_gh_msgq_info {
+	int  peer_id;
+	void *msgq_handle;
+	int  msgq_label;
+	struct notifier_block pvt_nb;
+};
+
+/**
+ * struct mmrm_vm_msg_q -- svm mmrm API caller queue that wait for mmrm API return
+ * @link: list head
+ * @m_req: request message pointer
+ * @m_resp: response message buffer pointer
+ * @complete: sync mmrm API response and caller
+ */
+struct mmrm_vm_msg_q {
+	struct list_head link;
+	struct mmrm_vm_request_msg_pkt *m_req;
+	struct mmrm_vm_response_msg_pkt *m_resp;
+	struct completion complete;
+};
+
+/**
+ * mmrm_vm_msgq_init - initialize display message queue: both TX and RX
+ * @mmrm_vm - handle to mmrm_vm_data_priv
+ */
+int mmrm_vm_msgq_init(struct mmrm_vm_driver_data *mmrm_vm);
+
+/**
+ * mmrm_vm_msgq_deinit - deinitialize display message queue: both TX and RX
+ * @mmrm_vm - handle to mmrm_vm_data_priv
+ */
+int mmrm_vm_msgq_deinit(struct mmrm_vm_driver_data *mmrm_vm);
+
+/**
+ * mmrm_vm_msgq_send - send custom messages across VM's
+ * @mmrm_vm - handle to mmrm_vm_data_priv
+ * @msg - payload data
+ * @msg_size - size of the payload_data
+ */
+int mmrm_vm_msgq_send(struct mmrm_vm_driver_data *mmrm_vm, void *msg, size_t msg_size);
+#endif // __MMRM_VM_MSGQ_H__
+

+ 44 - 0
vm/common/src/mmrm_vm_debug.c

@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/slab.h>
+
+#include "mmrm_vm_debug.h"
+
+int mmrm_vm_debug = MMRM_VM_ERR | MMRM_VM_WARN | MMRM_VM_PRINTK;
+
+/**
+ * msm_mmrm_debugfs_init - init debug sys entry
+ */
+struct dentry *msm_mmrm_debugfs_init(void)
+{
+	struct dentry *dir;
+
+	/* create a directory in debugfs root (/sys/kernel/debug) */
+	dir = debugfs_create_dir("mmrm_vm", NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		d_mpr_e("%s: Call to debugfs_create_dir(%s) failed!\n", __func__, "mmrm");
+		goto failed_create_dir;
+	}
+
+	/* add other params here */
+	debugfs_create_u32("debug_level", 0644, dir, &mmrm_vm_debug);
+
+	return dir;
+
+failed_create_dir:
+	d_mpr_e("%s: error\n", __func__);
+	return NULL;
+}
+
+/**
+ * msm_mmrm_debugfs_deinit - de-init debug sys entry
+ * dir: directory in debugfs root
+ */
+void msm_mmrm_debugfs_deinit(struct dentry *dir)
+{
+	debugfs_remove_recursive(dir);
+}
+