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 */