|
@@ -18,9 +18,122 @@ static int cvp_msgq_receiver(void *data)
|
|
{
|
|
{
|
|
struct cvp_msgq_drv *msgq_drv = data;
|
|
struct cvp_msgq_drv *msgq_drv = data;
|
|
|
|
|
|
|
|
+ struct cvp_ipc_msg *msg_ptr;
|
|
|
|
+ size_t size;
|
|
|
|
+ bool is_resp;
|
|
|
|
+ /**
|
|
|
|
+ * true: response received from remote VM, cmd initiated from LOCAL VM;
|
|
|
|
+ * false: cmd initiated from REMOTE VM;
|
|
|
|
+ */
|
|
|
|
+ int rc = -1;
|
|
if (IS_ERR_OR_NULL(msgq_drv))
|
|
if (IS_ERR_OR_NULL(msgq_drv))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
+ msg_ptr = kzalloc(sizeof(*msg_ptr), GFP_KERNEL);
|
|
|
|
+ if (!msg_ptr) {
|
|
|
|
+ dprintk(CVP_ERR, "%s: fail to allocate mem\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (true) {
|
|
|
|
+ rc = gh_msgq_recv(msgq_drv->config.handle, msg_ptr,
|
|
|
|
+ GH_MSGQ_MAX_MSG_SIZE_BYTES, &size, 0);
|
|
|
|
+
|
|
|
|
+ if (rc != 0 ) {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: gh_msgq_recv fail rc=%d handle=%#x msg_ptr=%#x\n",
|
|
|
|
+ __func__, rc, msgq_drv->config.handle, msg_ptr);
|
|
|
|
+
|
|
|
|
+ if (rc != -EAGAIN) {
|
|
|
|
+ kfree(msg_ptr);
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ is_resp = (msg_ptr->type &
|
|
|
|
+ CVP_IPC_MSG_TYPE_DIR_CHECK) ? true : false;
|
|
|
|
+
|
|
|
|
+ if (is_resp == false) {
|
|
|
|
+ dprintk(CVP_VM,
|
|
|
|
+ "%s: gh_msgq_recv cmd from remote VM\n",
|
|
|
|
+ __func__);
|
|
|
|
+
|
|
|
|
+ if (msgq_drv->pending_local_cmd.type == 0) {
|
|
|
|
+
|
|
|
|
+ /* copy ipc message to local cmd */
|
|
|
|
+ memcpy(&msgq_drv->pending_local_cmd,
|
|
|
|
+ msg_ptr, sizeof(struct cvp_ipc_msg));
|
|
|
|
+
|
|
|
|
+ /* toggle the direction bit*/
|
|
|
|
+ msgq_drv->pending_local_cmd.type ^=
|
|
|
|
+ CVP_IPC_MSG_TYPE_DIR_CHECK;
|
|
|
|
+
|
|
|
|
+ /* TODO: call client function ptr to process */
|
|
|
|
+
|
|
|
|
+ memcpy(msg_ptr, &msgq_drv->pending_local_cmd,
|
|
|
|
+ sizeof(struct cvp_ipc_msg));
|
|
|
|
+
|
|
|
|
+ /* 4: elements before actual data in cvp_ipc_msg*/
|
|
|
|
+ size = (4 + msgq_drv->pending_local_cmd.len)<<2;
|
|
|
|
+
|
|
|
|
+ /* sanity check on size information */
|
|
|
|
+ if (size > GH_MSGQ_MAX_MSG_SIZE_BYTES) {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: msg size %d exceed max size supported %d \n",
|
|
|
|
+ __func__, size, GH_MSGQ_MAX_MSG_SIZE_BYTES);
|
|
|
|
+ rc = -E2BIG;
|
|
|
|
+ msgq_drv->pending_local_cmd.type = 0;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* send it back to the remote VM as response */
|
|
|
|
+ rc = gh_msgq_send(msgq_drv->config.handle,
|
|
|
|
+ msg_ptr, size, GH_MSGQ_TX_PUSH);
|
|
|
|
+
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: failed gh_msgq_send rc %d \n",
|
|
|
|
+ __func__, rc);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* flag the source is released */
|
|
|
|
+ msgq_drv->pending_local_cmd.type = 0;
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: Msg rejected, local cmd in use type %d\n",
|
|
|
|
+ __func__, msgq_drv->pending_local_cmd.type);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ dprintk(CVP_VM,
|
|
|
|
+ "%s: gh_msgq_recv respond type from remote VM\n",
|
|
|
|
+ __func__);
|
|
|
|
+
|
|
|
|
+ if ((msg_ptr->type & CVP_IPC_MSG_TYPE_ACT_CHECK) !=
|
|
|
|
+ msgq_drv->pending_remote_rsp.type) {
|
|
|
|
+
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: Msg disgard,recv type %d, pend local %d\n",
|
|
|
|
+ __func__, msg_ptr->type,
|
|
|
|
+ msgq_drv->pending_remote_rsp.type);
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ /* memcpy received data to pending_remote_rsp */
|
|
|
|
+ memcpy(&msgq_drv->pending_remote_rsp, msg_ptr,
|
|
|
|
+ sizeof(struct cvp_ipc_msg));
|
|
|
|
+
|
|
|
|
+ /* clear direction bit of pending_remote_rsp */
|
|
|
|
+ msgq_drv->pending_remote_rsp.type &=
|
|
|
|
+ (~CVP_IPC_MSG_TYPE_DIR_CHECK);
|
|
|
|
+
|
|
|
|
+ /* complete for cmd initiated from local VM */
|
|
|
|
+ complete(&msgq_drv->completions[
|
|
|
|
+ msgq_drv->pending_remote_rsp.type - 1]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -39,12 +152,13 @@ static int cvp_complete_msgq_init(struct cvp_msgq_drv *msgq_drv)
|
|
|
|
|
|
mutex_init(&msgq_drv->ipc_lock);
|
|
mutex_init(&msgq_drv->ipc_lock);
|
|
|
|
|
|
- for (i = 0; i <= CVP_MAX_IPC_CMD; i++)
|
|
|
|
|
|
+ for (i = 0; i <= (CVP_MAX_IPC_CMD - 1); i++)
|
|
init_completion(&msgq_drv->completions[i]);
|
|
init_completion(&msgq_drv->completions[i]);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifndef CONFIG_EVA_TVM
|
|
static int cvp_msgq_cb(struct notifier_block *nb,
|
|
static int cvp_msgq_cb(struct notifier_block *nb,
|
|
unsigned long cmd, void *data)
|
|
unsigned long cmd, void *data)
|
|
{
|
|
{
|
|
@@ -55,7 +169,6 @@ static int cvp_msgq_cb(struct notifier_block *nb,
|
|
gh_vmid_t self_vmid;
|
|
gh_vmid_t self_vmid;
|
|
int rc;
|
|
int rc;
|
|
|
|
|
|
-
|
|
|
|
if (IS_ERR_OR_NULL(nb))
|
|
if (IS_ERR_OR_NULL(nb))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
@@ -83,8 +196,8 @@ static int cvp_msgq_cb(struct notifier_block *nb,
|
|
if (peer_vmid != vm_status_payload->vmid)
|
|
if (peer_vmid != vm_status_payload->vmid)
|
|
return NOTIFY_DONE;
|
|
return NOTIFY_DONE;
|
|
|
|
|
|
- dprintk(CVP_VM, "%s vmid=%d, peer_vmid=%d\n", vm_status_payload->vmid,
|
|
|
|
- peer_vmid);
|
|
|
|
|
|
+ dprintk(CVP_VM, "%s: vmid=%d, peer_vmid=%d\n",
|
|
|
|
+ __func__, vm_status_payload->vmid, peer_vmid);
|
|
|
|
|
|
if (msgq_config->handle)
|
|
if (msgq_config->handle)
|
|
return -15;
|
|
return -15;
|
|
@@ -95,11 +208,14 @@ static int cvp_msgq_cb(struct notifier_block *nb,
|
|
dprintk(CVP_ERR, "PVM failed to register msgq %d\n", rc);
|
|
dprintk(CVP_ERR, "PVM failed to register msgq %d\n", rc);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
+ dprintk(CVP_VM, "%s: gh_msgq_register handle: %x\n",
|
|
|
|
+ __func__, msgq_config->handle);
|
|
|
|
|
|
rc = cvp_complete_msgq_init(msgq_drv);
|
|
rc = cvp_complete_msgq_init(msgq_drv);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
|
|
static int cvp_msgq_init(struct cvp_msgq_drv *msgq_drv)
|
|
static int cvp_msgq_init(struct cvp_msgq_drv *msgq_drv)
|
|
{
|
|
{
|
|
@@ -111,11 +227,13 @@ static int cvp_msgq_init(struct cvp_msgq_drv *msgq_drv)
|
|
/* PVM init */
|
|
/* PVM init */
|
|
msgq_drv->config.peer_id = GH_TRUSTED_VM;
|
|
msgq_drv->config.peer_id = GH_TRUSTED_VM;
|
|
msgq_drv->config.rm_nb.notifier_call = cvp_msgq_cb;
|
|
msgq_drv->config.rm_nb.notifier_call = cvp_msgq_cb;
|
|
|
|
+
|
|
rc = gh_rm_register_notifier(&msgq_drv->config.rm_nb);
|
|
rc = gh_rm_register_notifier(&msgq_drv->config.rm_nb);
|
|
if (rc) {
|
|
if (rc) {
|
|
dprintk(CVP_ERR, "PVM Fail register msgq notifier %d\n", rc);
|
|
dprintk(CVP_ERR, "PVM Fail register msgq notifier %d\n", rc);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
+ dprintk(CVP_VM, "%s: gh_rm_register_notifier\n", __func__);
|
|
#else
|
|
#else
|
|
/* TVM init */
|
|
/* TVM init */
|
|
msgq_drv->config.handle = gh_msgq_register(GH_MSGQ_LABEL_EVA);
|
|
msgq_drv->config.handle = gh_msgq_register(GH_MSGQ_LABEL_EVA);
|
|
@@ -124,7 +242,7 @@ static int cvp_msgq_init(struct cvp_msgq_drv *msgq_drv)
|
|
dprintk(CVP_ERR, "TVM failed to register msgq %d\n", rc);
|
|
dprintk(CVP_ERR, "TVM failed to register msgq %d\n", rc);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
- rc = cvp_msgq_complete_init(msgq_drv);
|
|
|
|
|
|
+ rc = cvp_complete_msgq_init(msgq_drv);
|
|
#endif
|
|
#endif
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -137,22 +255,84 @@ static int cvp_msgq_deinit(struct cvp_msgq_drv *msgq_drv)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int cvp_msgq_send(struct cvp_msgq_drv *msgq_drv,
|
|
|
|
|
|
+static int cvp_msgq_send_cmd(struct cvp_msgq_drv *msgq_drv,
|
|
void *msg, size_t msg_size)
|
|
void *msg, size_t msg_size)
|
|
{
|
|
{
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
|
|
+ int rc = -1;
|
|
|
|
|
|
-static int cvp_msgq_receive(struct cvp_msgq_drv *msgq_drv)
|
|
|
|
-{
|
|
|
|
- return 0;
|
|
|
|
|
|
+ struct cvp_ipc_msg *msg_ptr = msg;
|
|
|
|
+
|
|
|
|
+ if (!msgq_drv->config.handle) {
|
|
|
|
+ dprintk(CVP_ERR, "%s: Invalid msgq handle\n", __func__);
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto err_param_check;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (msg_size > GH_MSGQ_MAX_MSG_SIZE_BYTES) {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: msg size %d exceed max size supported %d \n",
|
|
|
|
+ __func__, msg_size, GH_MSGQ_MAX_MSG_SIZE_BYTES);
|
|
|
|
+ rc = -E2BIG;
|
|
|
|
+ goto err_param_check;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mutex_lock(&msgq_drv->ipc_lock);
|
|
|
|
+
|
|
|
|
+ /* init case: only allow sending msg sequentially */
|
|
|
|
+ if (msgq_drv->pending_remote_rsp.type &
|
|
|
|
+ CVP_IPC_MSG_TYPE_ACT_CHECK) {
|
|
|
|
+ rc = -EPERM;
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: Msg rejected, local rsp occupied.\n",
|
|
|
|
+ __func__);
|
|
|
|
+
|
|
|
|
+ goto err_valid_check;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* book keeping type bits in pending_remote_rsp */
|
|
|
|
+ msgq_drv->pending_remote_rsp.type = msg_ptr->type;
|
|
|
|
+
|
|
|
|
+ rc = gh_msgq_send(msgq_drv->config.handle,
|
|
|
|
+ msg_ptr, msg_size, GH_MSGQ_TX_PUSH);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ dprintk(CVP_ERR,
|
|
|
|
+ "%s: failed with gh_msgq_send with rc %d \n",
|
|
|
|
+ __func__, rc);
|
|
|
|
+ goto err_gh_send;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* wait for completion */
|
|
|
|
+ if (!wait_for_completion_timeout(
|
|
|
|
+ &msgq_drv->completions[msgq_drv->pending_remote_rsp.type - 1],
|
|
|
|
+ msecs_to_jiffies(CVP_VM_RESPONSE_TIMEOUT))) {
|
|
|
|
+ dprintk(CVP_ERR, "%s cvp ipc msg type %d timeout\n",
|
|
|
|
+ __func__, msgq_drv->pending_remote_rsp.type-1);
|
|
|
|
+ rc = -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* copy pending_remote_rsp content to msg (inout param)*/
|
|
|
|
+ memcpy(msg, &msgq_drv->pending_remote_rsp,
|
|
|
|
+ sizeof(struct cvp_ipc_msg));
|
|
|
|
+
|
|
|
|
+ /* clear type bits to indicate resource is avaialbel */
|
|
|
|
+ msgq_drv->pending_remote_rsp.type = 0;
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&msgq_drv->ipc_lock);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+
|
|
|
|
+err_gh_send:
|
|
|
|
+err_valid_check:
|
|
|
|
+ mutex_unlock(&msgq_drv->ipc_lock);
|
|
|
|
+err_param_check:
|
|
|
|
+ return rc;
|
|
}
|
|
}
|
|
|
|
|
|
static struct cvp_msgq_ops msgq_ops = {
|
|
static struct cvp_msgq_ops msgq_ops = {
|
|
.msgq_init = cvp_msgq_init,
|
|
.msgq_init = cvp_msgq_init,
|
|
.msgq_deinit = cvp_msgq_deinit,
|
|
.msgq_deinit = cvp_msgq_deinit,
|
|
- .msgq_send = cvp_msgq_send,
|
|
|
|
- .msgq_receive = cvp_msgq_receive,
|
|
|
|
|
|
+ .msgq_send = cvp_msgq_send_cmd,
|
|
|
|
+ .msgq_receive = NULL,
|
|
};
|
|
};
|
|
|
|
|
|
struct cvp_msgq_drv cvp_ipc_msgq = {
|
|
struct cvp_msgq_drv cvp_ipc_msgq = {
|