From 66af98dc3f166a24fae4e6a09e512656e0fa72c9 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 11 Jun 2020 13:11:33 -0700 Subject: [PATCH] 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: Chris Lew --- net/neuron/channel/ch_haven_recv.c | 81 +++++++++++++++++++++++++ net/neuron/channel/ch_haven_send.c | 79 ++++++++++++++++++++++++ net/neuron/channel/ch_mq_shmem_common.h | 4 ++ 3 files changed, 164 insertions(+) diff --git a/net/neuron/channel/ch_haven_recv.c b/net/neuron/channel/ch_haven_recv.c index ae50c5a72aa6..b14525587664 100644 --- a/net/neuron/channel/ch_haven_recv.c +++ b/net/neuron/channel/ch_haven_recv.c @@ -21,6 +21,7 @@ #include #include #include +#include #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; diff --git a/net/neuron/channel/ch_haven_send.c b/net/neuron/channel/ch_haven_send.c index 4b0c2d44621c..da6238371c63 100644 --- a/net/neuron/channel/ch_haven_send.c +++ b/net/neuron/channel/ch_haven_send.c @@ -21,6 +21,7 @@ #include #include #include +#include #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; diff --git a/net/neuron/channel/ch_mq_shmem_common.h b/net/neuron/channel/ch_mq_shmem_common.h index 10f3381ce590..7b9b90f2f590 100644 --- a/net/neuron/channel/ch_mq_shmem_common.h +++ b/net/neuron/channel/ch_mq_shmem_common.h @@ -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 */