// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020 MediaTek Inc. */ #include #include #include #include #include #include "reviser_cmn.h" #include "reviser_drv.h" #include "reviser_remote.h" #include "reviser_msg.h" struct reviser_msg_item { struct reviser_msg msg; struct list_head list; }; struct reviser_msg *g_reply; struct reviser_msg_mgr *g_rvr_msg; static struct reviser_msg g_reviser_msg_reply; static struct reviser_msg_mgr g_msg_mgr; bool reviser_is_remote(void) { bool is_remote = false; mutex_lock(&g_rvr_msg->lock.mutex_mgr); if (g_rvr_msg->info.init) { //LOG_ERR("Can Not Read when rv disable\n"); is_remote = true; } mutex_unlock(&g_rvr_msg->lock.mutex_mgr); return is_remote; } int reviser_remote_init(void) { DEBUG_TAG; mutex_init(&g_msg_mgr.lock.mutex_cmd); mutex_init(&g_msg_mgr.lock.mutex_ipi); mutex_init(&g_msg_mgr.lock.mutex_mgr); spin_lock_init(&g_msg_mgr.lock.lock_rx); init_waitqueue_head(&g_msg_mgr.lock.wait_rx); INIT_LIST_HEAD(&g_msg_mgr.list_rx); g_reply = &g_reviser_msg_reply; g_reply->sn = 0; g_msg_mgr.count = 0; g_rvr_msg = &g_msg_mgr; g_msg_mgr.info.init = true; return 0; } void reviser_remote_exit(void) { DEBUG_TAG; g_msg_mgr.info.init = false; g_reply->sn = 0; } int reviser_remote_send_cmd_sync(void *drvinfo, void *request, void *reply, uint32_t timeout) { // TODO No timeout struct reviser_dev_info *rdv = NULL; int ret = 0; unsigned long flags; struct reviser_msg_item *item; struct list_head *tmp = NULL, *pos = NULL; struct reviser_msg *rmesg, *snd_rmesg; int retry = 0; bool find = false; uint32_t *ptr; uint32_t cnt = 100, i = 0; if (drvinfo == NULL) { LOG_ERR("invalid argument\n"); return -EINVAL; } rdv = (struct reviser_dev_info *)drvinfo; snd_rmesg = (struct reviser_msg *) request; mutex_lock(&g_rvr_msg->lock.mutex_cmd); mutex_lock(&g_rvr_msg->lock.mutex_ipi); snd_rmesg->sn = g_rvr_msg->send_sn; g_rvr_msg->send_sn++; ptr = (uint32_t *)request; LOG_DBG_RVR_FLW("Send [%x][%x][%x][%x][%x][%x][%x][%x]\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); /* send & retry */ for (i = 0; i < cnt; i++) { ret = rpmsg_send(rdv->rpdev->ept, request, sizeof(struct reviser_msg)); /* send busy, retry */ if (ret == -EBUSY || ret == -EAGAIN) { if (!(i % 10)) LOG_INFO("re-send ipi(%u/%u)\n", i, cnt); if (ret == -EAGAIN && i < 10) usleep_range(200, 500); else if (ret == -EAGAIN && i < 50) usleep_range(1000, 2000); else usleep_range(10000, 11000); continue; } break; } mutex_unlock(&g_rvr_msg->lock.mutex_ipi); if (ret) { LOG_ERR("Send Reviser IPI Fail %d\n", ret); goto out; } wait: LOG_DBG_RVR_FLW("Wait for Getting cmd\n"); ret = wait_event_interruptible_timeout( g_rvr_msg->lock.wait_rx, g_rvr_msg->count, msecs_to_jiffies(REVISER_REMOTE_TIMEOUT)); if (ret == -ERESTARTSYS) { LOG_ERR("Wake up by signal!, retry again %d\n", retry); msleep(20); retry++; goto wait; } if (!ret) { LOG_ERR("wait command timeout!!\n"); ret = -ETIME; goto out; } spin_lock_irqsave(&g_rvr_msg->lock.lock_rx, flags); list_for_each_safe(pos, tmp, &g_rvr_msg->list_rx) { item = list_entry(pos, struct reviser_msg_item, list); list_del(pos); g_rvr_msg->count--; rmesg = (struct reviser_msg *) &item->msg; LOG_DBG_RVR_FLW("item sn(%d) cmd(%x) option(%x) ack (%x)\n", rmesg->sn, rmesg->cmd, rmesg->option, rmesg->ack); memcpy(reply, rmesg, sizeof(struct reviser_msg)); find = true; break; } spin_unlock_irqrestore(&g_rvr_msg->lock.lock_rx, flags); if (find) vfree(item); ret = 0; out: mutex_unlock(&g_rvr_msg->lock.mutex_cmd); return ret; } int reviser_remote_rx_cb(void *data, int len) { unsigned long flags; struct reviser_msg_item *item; uint32_t *ptr; if (len != sizeof(struct reviser_msg)) { LOG_ERR("invalid len %d / %d\n", len, sizeof(struct reviser_msg)); return -EINVAL; } item = vzalloc(sizeof(*item)); memcpy(&item->msg, data, len); ptr = (uint32_t *)data; LOG_DBG_RVR_FLW("Rcv [%x][%x][%x][%x][%x][%x][%x][%x]\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); spin_lock_irqsave(&g_rvr_msg->lock.lock_rx, flags); list_add_tail(&item->list, &g_rvr_msg->list_rx); g_rvr_msg->count++; spin_unlock_irqrestore(&g_rvr_msg->lock.lock_rx, flags); wake_up_interruptible(&g_rvr_msg->lock.wait_rx); return 0; } int reviser_remote_sync_sn(void *drvinfo, uint32_t sn) { mutex_lock(&g_rvr_msg->lock.mutex_mgr); g_rvr_msg->send_sn = sn; mutex_unlock(&g_rvr_msg->lock.mutex_mgr); return 0; }