Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66af98dc authored by Chris Lew's avatar Chris Lew
Browse files

neuron: ch_haven: Add memory sharing support



The carved out or allocated memory may not be configured to be
accessible by both the owner and consumer vms. Add support to share
memory through hyp_assign_phy() and assign a label to the resultant
memparcel through hh_rm_mem_qcom_lookup_sgl().

This sharing sequence should only be done by the owner of the reserved
memory region. Currently we indicate this with the qcom,primary tag in
device tree.

Change-Id: Idf5658ab4cf0d1c022f6b919914a8e782318c8d7
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 6826400d
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <asm-generic/barrier.h>
#include <linux/haven/hh_rm_drv.h>
#include <linux/haven/hh_dbl.h>
#include <soc/qcom/secure_buffer.h>
#include "ch_mq_shmem_common.h"

#define CHANNEL_VERSION NEURON_SHMEM_CHANNEL_V1
@@ -295,6 +296,82 @@ static int channel_sync_thread(void *data)
	return 0;
}

static int channel_hh_share_mem(struct neuron_mq_data_priv *priv,
				hh_vmid_t self, hh_vmid_t peer)
{
	u32 src_vmlist[1] = {self};
	int dst_vmlist[2] = {self, peer};
	int dst_perms[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE};
	struct hh_acl_desc *acl;
	struct hh_sgl_desc *sgl;
	int ret;

	ret = hyp_assign_phys(priv->buffer.start, resource_size(&priv->buffer),
			      src_vmlist, 1,
			      dst_vmlist, dst_perms, 2);
	if (ret) {
		pr_err("hyp_assign_phys failed addr=%x size=%u err=%d\n",
		       priv->buffer.start, resource_size(&priv->buffer), ret);
		return ret;
	}

	acl = kzalloc(offsetof(struct hh_acl_desc, acl_entries[2]), GFP_KERNEL);
	if (!acl)
		return -ENOMEM;
	sgl = kzalloc(offsetof(struct hh_sgl_desc, sgl_entries[1]), GFP_KERNEL);
	if (!sgl) {
		kfree(acl);
		return -ENOMEM;
	}

	acl->n_acl_entries = 2;
	acl->acl_entries[0].vmid = (u16)self;
	acl->acl_entries[0].perms = HH_RM_ACL_R | HH_RM_ACL_W;
	acl->acl_entries[1].vmid = (u16)peer;
	acl->acl_entries[1].perms = HH_RM_ACL_R | HH_RM_ACL_W;

	sgl->n_sgl_entries = 1;
	sgl->sgl_entries[0].ipa_base = priv->buffer.start;
	sgl->sgl_entries[0].size = resource_size(&priv->buffer);
	ret = hh_rm_mem_qcom_lookup_sgl(HH_RM_MEM_TYPE_NORMAL,
					priv->haven_label,
					acl, sgl, NULL,
					&priv->shm_memparcel);
	kfree(acl);
	kfree(sgl);

	return ret;
}

static int channel_hh_rm_cb(struct notifier_block *nb, unsigned long cmd,
			    void *data)
{
	struct hh_rm_notif_vm_status_payload *vm_status_payload;
	struct neuron_mq_data_priv *priv;
	hh_vmid_t peer_vmid;
	hh_vmid_t self_vmid;

	priv = container_of(nb, struct neuron_mq_data_priv, rm_nb);

	if (cmd != HH_RM_NOTIF_VM_STATUS)
		return NOTIFY_DONE;

	vm_status_payload = data;
	if (vm_status_payload->vm_status != HH_RM_VM_STATUS_READY)
		return NOTIFY_DONE;
	if (hh_rm_get_vmid(priv->peer_name, &peer_vmid))
		return NOTIFY_DONE;
	if (hh_rm_get_vmid(HH_PRIMARY_VM, &self_vmid))
		return NOTIFY_DONE;
	if (peer_vmid != vm_status_payload->vmid)
		return NOTIFY_DONE;

	if (channel_hh_share_mem(priv, self_vmid, peer_vmid))
		pr_err("%s: failed to share memory\n", __func__);

	return NOTIFY_DONE;
}

static int channel_hh_map_memory(struct neuron_mq_data_priv *priv,
				 struct device *dev)
{
@@ -344,6 +421,10 @@ static int channel_hh_map_memory(struct neuron_mq_data_priv *priv,
					   &priv->peer_name);
		if (ret)
			priv->peer_name = HH_SELF_VM;

		priv->rm_nb.notifier_call = channel_hh_rm_cb;
		priv->rm_nb.priority = INT_MAX;
		hh_rm_register_notifier(&priv->rm_nb);
	}

	return 0;
+79 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <asm-generic/barrier.h>
#include <linux/haven/hh_rm_drv.h>
#include <linux/haven/hh_dbl.h>
#include <soc/qcom/secure_buffer.h>
#include "ch_mq_shmem_common.h"

#define CHANNEL_VERSION NEURON_SHMEM_CHANNEL_V1
@@ -280,6 +281,80 @@ static int channel_sync_thread(void *data)
	return 0;
}

static int channel_hh_share_mem(struct neuron_mq_data_priv *priv,
				hh_vmid_t self, hh_vmid_t peer)
{
	u32 src_vmlist[1] = {self};
	int dst_vmlist[2] = {self, peer};
	int dst_perms[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE};
	struct hh_acl_desc *acl;
	struct hh_sgl_desc *sgl;
	int ret;

	ret = hyp_assign_phys(priv->buffer.start, resource_size(&priv->buffer),
			      src_vmlist, 1,
			      dst_vmlist, dst_perms, 2);
	if (ret) {
		pr_err("hyp_assign_phys failed addr=%x size=%u err=%d\n",
		       priv->buffer.start, resource_size(&priv->buffer), ret);
		return ret;
	}

	acl = kzalloc(offsetof(struct hh_acl_desc, acl_entries[2]), GFP_KERNEL);
	if (!acl)
		return -ENOMEM;
	sgl = kzalloc(offsetof(struct hh_sgl_desc, sgl_entries[1]), GFP_KERNEL);
	if (!sgl) {
		kfree(acl);
		return -ENOMEM;
	}

	acl->n_acl_entries = 2;
	acl->acl_entries[0].vmid = (u16)self;
	acl->acl_entries[0].perms = HH_RM_ACL_R | HH_RM_ACL_W;
	acl->acl_entries[1].vmid = (u16)peer;
	acl->acl_entries[1].perms = HH_RM_ACL_R | HH_RM_ACL_W;

	sgl->n_sgl_entries = 1;
	sgl->sgl_entries[0].ipa_base = priv->buffer.start;
	sgl->sgl_entries[0].size = resource_size(&priv->buffer);
	ret = hh_rm_mem_qcom_lookup_sgl(HH_RM_MEM_TYPE_NORMAL,
					priv->haven_label,
					acl, sgl, NULL,
					&priv->shm_memparcel);
	kfree(acl);
	kfree(sgl);

	return ret;
}

static int channel_hh_rm_cb(struct notifier_block *nb, unsigned long cmd,
			    void *data)
{
	struct hh_rm_notif_vm_status_payload *vm_status_payload = data;
	struct neuron_mq_data_priv *priv;
	hh_vmid_t peer_vmid;
	hh_vmid_t self_vmid;

	priv = container_of(nb, struct neuron_mq_data_priv, rm_nb);
	if (cmd != HH_RM_NOTIF_VM_STATUS)
		return NOTIFY_DONE;

	if (vm_status_payload->vm_status != HH_RM_VM_STATUS_READY)
		return NOTIFY_DONE;
	if (hh_rm_get_vmid(priv->peer_name, &peer_vmid))
		return NOTIFY_DONE;
	if (hh_rm_get_vmid(HH_PRIMARY_VM, &self_vmid))
		return NOTIFY_DONE;
	if (peer_vmid != vm_status_payload->vmid)
		return NOTIFY_DONE;

	if (channel_hh_share_mem(priv, self_vmid, peer_vmid))
		pr_err("%s: failed to share memory\n", __func__);

	return NOTIFY_DONE;
}

static int channel_hh_map_memory(struct neuron_mq_data_priv *priv,
				 struct device *dev)
{
@@ -329,6 +404,10 @@ static int channel_hh_map_memory(struct neuron_mq_data_priv *priv,
					   &priv->peer_name);
		if (ret)
			priv->peer_name = HH_SELF_VM;

		priv->rm_nb.notifier_call = channel_hh_rm_cb;
		priv->rm_nb.priority = INT_MAX;
		hh_rm_register_notifier(&priv->rm_nb);
	}

	return 0;
+4 −0
Original line number Diff line number Diff line
@@ -84,6 +84,10 @@ struct neuron_mq_data_priv {
	void *tx_dbl;
	/* haven rx doorbell descriptor */
	void *rx_dbl;
	/* memparcel handle after assigning label to shared memory */
	u32 shm_memparcel;
	/* haven rm status notifier block */
	struct notifier_block rm_nb;
	/* pointer to the device structure */
	struct neuron_channel *dev;
	/* shared memory mapped address */