From 04c6aea0028a1f2d8e995b2a0e29dfcb20d75ba5 Mon Sep 17 00:00:00 2001 From: George Shen Date: Wed, 4 Mar 2020 10:37:27 -0800 Subject: [PATCH] msm: cvp: Support CVP session flush Added cvp session flush support for Lahaina. Change-Id: Id1bd806abf5ab5b41ad876203016f54b58e73a82 Signed-off-by: George Shen --- drivers/media/platform/msm/cvp/cvp_hfi.c | 47 +- drivers/media/platform/msm/cvp/cvp_hfi.h | 12 +- drivers/media/platform/msm/cvp/cvp_hfi_api.h | 4 +- .../media/platform/msm/cvp/cvp_hfi_helper.h | 9 + .../platform/msm/cvp/hfi_response_handler.c | 28 + drivers/media/platform/msm/cvp/msm_cvp.c | 586 +++++++++++++++--- .../media/platform/msm/cvp/msm_cvp_common.c | 20 +- drivers/media/platform/msm/cvp/msm_cvp_core.c | 18 +- .../media/platform/msm/cvp/msm_cvp_internal.h | 12 +- .../media/platform/msm/cvp/msm_cvp_ioctl.c | 152 ++++- 10 files changed, 766 insertions(+), 122 deletions(-) diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c index c9b13f6198f6..47225d63e80f 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.c +++ b/drivers/media/platform/msm/cvp/cvp_hfi.c @@ -2447,6 +2447,28 @@ err_send_pkt: return rc; } +static int iris_hfi_session_flush(void *sess) +{ + struct cvp_hal_session *session = sess; + struct iris_hfi_device *device; + int rc = 0; + + if (!session || !session->device) { + dprintk(CVP_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + device = session->device; + + mutex_lock(&device->lock); + + rc = __send_session_cmd(session, HFI_CMD_SESSION_CVP_FLUSH); + + mutex_unlock(&device->lock); + + return rc; +} + static int __check_core_registered(struct iris_hfi_device *device, phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size, phys_addr_t irq) @@ -2673,26 +2695,20 @@ skip_power_off: return -EAGAIN; } -static void print_sfr_message(struct iris_hfi_device *device) +static void __process_sys_error(struct iris_hfi_device *device) { struct cvp_hfi_sfr_struct *vsfr = NULL; - u32 vsfr_size = 0; - void *p = NULL; vsfr = (struct cvp_hfi_sfr_struct *)device->sfr.align_virtual_addr; if (vsfr) { - if (vsfr->bufSize != device->sfr.mem_size) { - dprintk(CVP_ERR, "Invalid SFR buf size %d actual %d\n", - vsfr->bufSize, device->sfr.mem_size); - return; - } - vsfr_size = vsfr->bufSize - sizeof(u32); - p = memchr(vsfr->rg_data, '\0', vsfr_size); + void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize); /* * SFR isn't guaranteed to be NULL terminated + * since SYS_ERROR indicates that Iris is in the + * process of crashing. */ if (p == NULL) - vsfr->rg_data[vsfr_size - 1] = '\0'; + vsfr->rg_data[vsfr->bufSize - 1] = '\0'; dprintk(CVP_ERR, "SFR Message from FW: %s\n", vsfr->rg_data); @@ -2816,7 +2832,7 @@ static void process_system_msg(struct msm_cvp_cb_info *info, switch (info->response_type) { case HAL_SYS_ERROR: - print_sfr_message(device); + __process_sys_error(device); break; case HAL_SYS_RELEASE_RESOURCE_DONE: dprintk(CVP_DBG, "Received SYS_RELEASE_RESOURCE\n"); @@ -2925,6 +2941,8 @@ static int __response_handler(struct iris_hfi_device *device) } if (device->intr_status & CVP_FATAL_INTR_BMSK) { + struct cvp_hfi_sfr_struct *vsfr = (struct cvp_hfi_sfr_struct *) + device->sfr.align_virtual_addr; struct msm_cvp_cb_info info = { .response_type = HAL_SYS_WATCHDOG_TIMEOUT, .response.cmd = { @@ -2932,7 +2950,9 @@ static int __response_handler(struct iris_hfi_device *device) } }; - print_sfr_message(device); + if (vsfr) + dprintk(CVP_ERR, "SFR Message from FW: %s\n", + vsfr->rg_data); if (device->intr_status & CVP_WRAPPER_INTR_MASK_CPU_NOC_BMSK) dprintk(CVP_ERR, "Received Xtensa NOC error\n"); @@ -4585,6 +4605,7 @@ static void iris_init_hfi_callbacks(struct cvp_hfi_device *hdev) hdev->session_set_buffers = iris_hfi_session_set_buffers; hdev->session_release_buffers = iris_hfi_session_release_buffers; hdev->session_send = iris_hfi_session_send; + hdev->session_flush = iris_hfi_session_flush; hdev->scale_clocks = iris_hfi_scale_clocks; hdev->vote_bus = iris_hfi_vote_buses; hdev->get_fw_info = iris_hfi_get_fw_info; diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.h b/drivers/media/platform/msm/cvp/cvp_hfi.h index b52b47769d7c..9c6ff815a5cf 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi.h @@ -98,6 +98,8 @@ (HFI_CMD_SESSION_CVP_START + 0x054) #define HFI_CMD_SESSION_CVP_RELEASE_PERSIST_BUFFERS\ (HFI_CMD_SESSION_CVP_START + 0x055) +#define HFI_CMD_SESSION_CVP_FLUSH\ + (HFI_CMD_SESSION_CVP_START + 0x057) #define HFI_CMD_SESSION_CVP_ICA_FRAME\ (HFI_CMD_SESSION_CVP_START + 0x100) #define HFI_CMD_SESSION_CVP_ICA_CONFIG\ @@ -136,14 +138,16 @@ (HFI_MSG_SESSION_CVP_START + 0x023) #define HFI_MSG_SESSION_CVP_OPERATION_CONFIG (HFI_MSG_SESSION_CVP_START + 0x030) -#define HFI_MSG_SESSION_CVP_SET_PERSIST_BUFFERS\ +#define HFI_MSG_SESSION_CVP_SET_PERSIST_BUFFERS\ (HFI_MSG_SESSION_CVP_START + 0x034) -#define HFI_MSG_SESSION_CVP_SET_MODEL_BUFFERS\ +#define HFI_MSG_SESSION_CVP_SET_MODEL_BUFFERS\ (HFI_MSG_SESSION_CVP_START + 0x036) -#define HFI_MSG_SESSION_CVP_FD\ +#define HFI_MSG_SESSION_CVP_FD\ (HFI_MSG_SESSION_CVP_START + 0x037) -#define HFI_MSG_SESSION_CVP_RELEASE_PERSIST_BUFFERS\ +#define HFI_MSG_SESSION_CVP_RELEASE_PERSIST_BUFFERS\ (HFI_MSG_SESSION_CVP_START + 0x038) +#define HFI_MSG_SESSION_CVP_FLUSH\ + (HFI_CMD_SESSION_CVP_START + 0x03A) #define CVP_IFACEQ_MAX_PKT_SIZE 1024 #define CVP_IFACEQ_MED_PKT_SIZE 768 diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_api.h b/drivers/media/platform/msm/cvp/cvp_hfi_api.h index e1eb9d4e96fe..152d5a4effcf 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_api.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_api.h @@ -340,8 +340,8 @@ struct cvp_hfi_device { int (*session_abort)(void *session); int (*session_set_buffers)(void *sess, u32 iova, u32 size); int (*session_release_buffers)(void *sess); - int (*session_send)(void *sess, - struct cvp_kmd_hfi_packet *in_pkt); + int (*session_send)(void *sess, struct cvp_kmd_hfi_packet *in_pkt); + int (*session_flush)(void *sess); int (*scale_clocks)(void *dev, u32 freq); int (*vote_bus)(void *dev, struct cvp_bus_vote_data *data, int num_data); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h index 0c79b47e9b54..bc79f7bffc13 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h @@ -48,6 +48,7 @@ #define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL (HFI_COMMON_BASE + 0x1011) #define HFI_ERR_SESSION_INVALID_SCALE_FACTOR (HFI_COMMON_BASE + 0x1012) #define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED (HFI_COMMON_BASE + 0x1013) +#define HFI_ERR_SESSION_FLUSHED (HFI_COMMON_BASE + 0x101C) #define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) #define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2) @@ -455,4 +456,12 @@ struct cvp_buf_type { }; }; +struct cvp_hfi_msg_sys_session_flush_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + struct cvp_hfi_client client_data; +}; + #endif diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index cd6480711436..1a8b62e57d8c 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -327,6 +327,31 @@ static int hfi_process_session_set_buf_done(u32 device_id, return 0; } +static int hfi_process_session_flush_done(u32 device_id, + struct cvp_hfi_msg_sys_session_flush_done_packet *pkt, + struct msm_cvp_cb_info *info) +{ + struct msm_cvp_cb_cmd_done cmd_done = {0}; + + dprintk(CVP_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", + pkt->session_id); + + if (!pkt || pkt->size < + sizeof(struct cvp_hfi_msg_sys_session_flush_done_packet)) { + dprintk(CVP_ERR, "%s: bad packet/packet size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_FLUSH_DONE; + info->response.cmd = cmd_done; + + return 0; +} static int hfi_process_session_rel_buf_done(u32 device_id, struct cvp_hfi_msg_session_hdr *pkt, @@ -610,6 +635,9 @@ int cvp_hfi_process_msg_packet(u32 device_id, case HFI_MSG_SYS_SESSION_ABORT_DONE: pkt_func = (pkt_func_def)hfi_process_session_abort_done; break; + case HFI_MSG_SESSION_CVP_FLUSH: + pkt_func = (pkt_func_def)hfi_process_session_flush_done; + break; case HFI_MSG_SESSION_CVP_OPERATION_CONFIG: case HFI_MSG_SESSION_CVP_SET_PERSIST_BUFFERS: case HFI_MSG_SESSION_CVP_RELEASE_PERSIST_BUFFERS: diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index 3c9b74ba36ec..876c8cad424b 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -13,7 +13,7 @@ struct cvp_power_level { unsigned long bw_sum; }; -void print_internal_buffer(u32 tag, const char *str, +static void print_internal_buffer(u32 tag, const char *str, struct msm_cvp_inst *inst, struct cvp_internal_buf *cbuf) { if (!(tag & msm_cvp_debug) || !inst || !cbuf) @@ -41,8 +41,8 @@ void print_smem(u32 tag, const char *str, struct msm_cvp_inst *inst, if (smem->dma_buf) { dprintk(tag, "%s: %x : %s size %d flags %#x iova %#x", str, - hash32_ptr(inst->session), smem->dma_buf->name, smem->size, - smem->flags, smem->device_addr); + hash32_ptr(inst->session), smem->dma_buf->name, + smem->size, smem->flags, smem->device_addr); } } @@ -419,7 +419,7 @@ exit: return 0; } -static u32 msm_cvp_map_buf_cpu(struct msm_cvp_inst *inst, +static u32 msm_cvp_map_frame_buf(struct msm_cvp_inst *inst, struct cvp_buf_type *buf, struct msm_cvp_frame *frame) { @@ -443,6 +443,7 @@ static u32 msm_cvp_map_buf_cpu(struct msm_cvp_inst *inst, if (!smem) return 0; + frame->bufs[nr].fd = buf->fd; frame->bufs[nr].smem = smem; frame->bufs[nr].size = buf->size; frame->bufs[nr].offset = buf->offset; @@ -459,7 +460,7 @@ static u32 msm_cvp_map_buf_cpu(struct msm_cvp_inst *inst, return iova; } -static void msm_cvp_unmap_buf_cpu(struct msm_cvp_frame *frame) +static void msm_cvp_unmap_frame_buf(struct msm_cvp_frame *frame) { u32 i; u32 type; @@ -503,7 +504,7 @@ static void msm_cvp_unmap_frame(struct msm_cvp_inst *inst, u64 ktid) mutex_unlock(&inst->frames.lock); if (found) - msm_cvp_unmap_buf_cpu(frame); + msm_cvp_unmap_frame_buf(frame); else dprintk(CVP_WARN, "%s frame %llu not found!\n", __func__, ktid); } @@ -555,6 +556,7 @@ static int cvp_wait_process_message(struct msm_cvp_inst *inst, struct cvp_kmd_hfi_packet *out) { struct cvp_session_msg *msg = NULL; + struct cvp_hfi_msg_session_hdr *hdr; int rc = 0; if (wait_event_timeout(sq->wq, @@ -578,11 +580,12 @@ static int cvp_wait_process_message(struct msm_cvp_inst *inst, goto exit; } - msm_cvp_unmap_frame(inst, msg->pkt.client_data.kdata); if (out) memcpy(out, &msg->pkt, sizeof(struct cvp_hfi_msg_session_hdr)); kmem_cache_free(cvp_driver->msg_cache, msg); + hdr = (struct cvp_hfi_msg_session_hdr *)out; + msm_cvp_unmap_frame(inst, hdr->client_data.kdata); exit: return rc; @@ -768,13 +771,13 @@ static int msm_cvp_map_frame(struct msm_cvp_inst *inst, if (buf->fd < 0 || !buf->size) continue; - iova = msm_cvp_map_buf_cpu(inst, buf, frame); + iova = msm_cvp_map_frame_buf(inst, buf, frame); if (!iova) { dprintk(CVP_ERR, "%s: buf %d register failed.\n", __func__, i); - msm_cvp_unmap_buf_cpu(frame); + msm_cvp_unmap_frame_buf(frame); return -EINVAL; } buf->fd = iova; @@ -854,8 +857,7 @@ static int msm_cvp_session_process_hfi( if (rc) goto exit; - rc = call_hfi_op(hdev, session_send, - (void *)inst->session, in_pkt); + rc = call_hfi_op(hdev, session_send, (void *)inst->session, in_pkt); if (rc) { dprintk(CVP_ERR, "%s: Failed in call_hfi_op %d, %x\n", @@ -892,15 +894,15 @@ static bool cvp_fence_wait(struct cvp_fence_queue *q, struct cvp_fence_command *f; *fence = NULL; - spin_lock(&q->lock); + mutex_lock(&q->lock); *state = q->state; if (*state != QUEUE_ACTIVE) { - spin_unlock(&q->lock); + mutex_unlock(&q->lock); return true; } if (list_empty(&q->wait_list)) { - spin_unlock(&q->lock); + mutex_unlock(&q->lock); return false; } @@ -908,7 +910,7 @@ static bool cvp_fence_wait(struct cvp_fence_queue *q, list_del_init(&f->list); list_add_tail(&q->sched_list, &f->list); - spin_unlock(&q->lock); + mutex_unlock(&q->lock); *fence = f; return true; @@ -927,8 +929,10 @@ static int cvp_fence_dme(struct msm_cvp_inst *inst, u32 *synx, struct cvp_hfi_device *hdev; struct cvp_session_queue *sq; struct synx_session ssid; + u32 hfi_err = HFI_ERR_NONE; + struct cvp_hfi_msg_session_hdr *hdr; - dprintk(CVP_DBG, "Enter %s\n", __func__); + dprintk(CVP_DBG, "%s %s\n", current->comm, __func__); hdev = inst->core->device; sq = &inst->session_queue_fence; @@ -941,8 +945,8 @@ static int cvp_fence_dme(struct msm_cvp_inst *inst, u32 *synx, if (h_synx) { rc = synx_wait(ssid, h_synx, timeout_ms); if (rc) { - dprintk(CVP_ERR, "%s: synx_wait %d failed\n", - __func__, i); + dprintk(CVP_ERR, "%s %s: synx_wait %d failed\n", + current->comm, __func__, i); synx_state = SYNX_STATE_SIGNALED_ERROR; goto exit; } @@ -959,14 +963,32 @@ static int cvp_fence_dme(struct msm_cvp_inst *inst, u32 *synx, rc = call_hfi_op(hdev, session_send, (void *)inst->session, (struct cvp_kmd_hfi_packet *)pkt); if (rc) { - dprintk(CVP_ERR, "%s: Failed in call_hfi_op %d, %x\n", __func__, - pkt->size, pkt->packet_type); + dprintk(CVP_ERR, "%s %s: Failed in call_hfi_op %d, %x\n", + current->comm, __func__, pkt->size, pkt->packet_type); synx_state = SYNX_STATE_SIGNALED_ERROR; goto exit; } timeout = msecs_to_jiffies(CVP_MAX_WAIT_TIME); - rc = cvp_wait_process_message(inst, sq, &ktid, timeout, NULL); + rc = cvp_wait_process_message(inst, sq, &ktid, timeout, + (struct cvp_kmd_hfi_packet *)pkt); + hdr = (struct cvp_hfi_msg_session_hdr *)pkt; + hfi_err = hdr->error_type; + if (rc) { + dprintk(CVP_ERR, "%s %s: cvp_wait_process_message rc %d\n", + current->comm, __func__, rc); + synx_state = SYNX_STATE_SIGNALED_ERROR; + goto exit; + } + if (hfi_err == HFI_ERR_SESSION_FLUSHED) { + dprintk(CVP_DBG, "%s %s: cvp_wait_process_message flushed\n", + current->comm, __func__); + synx_state = SYNX_STATE_SIGNALED_CANCEL; + } else if (hfi_err != HFI_ERR_NONE) { + dprintk(CVP_ERR, "%s %s: cvp_wait_process_message hfi err %d\n", + current->comm, __func__, hfi_err); + synx_state = SYNX_STATE_SIGNALED_CANCEL; + } exit: if (synx[FENCE_DME_ICA_ENABLED_IDX]) { @@ -974,8 +996,8 @@ exit: rc = synx_signal(ssid, h_synx, synx_state); if (rc) { - dprintk(CVP_ERR, "%s: synx_signal %d failed\n", - __func__, FENCE_DME_DS_IDX); + dprintk(CVP_ERR, "%s %s: synx_signal %d failed\n", + current->comm, __func__, FENCE_DME_DS_IDX); synx_state = SYNX_STATE_SIGNALED_ERROR; } } @@ -983,8 +1005,8 @@ exit: h_synx = synx[FENCE_DME_OUTPUT_IDX]; rc = synx_signal(ssid, h_synx, synx_state); if (rc) - dprintk(CVP_ERR, "%s: synx_signal %d failed\n", - __func__, FENCE_DME_OUTPUT_IDX); + dprintk(CVP_ERR, "%s %s: synx_signal %d failed\n", + current->comm, __func__, FENCE_DME_OUTPUT_IDX); return rc; } @@ -1003,8 +1025,10 @@ static int cvp_fence_proc(struct msm_cvp_inst *inst, u32 *synx, struct cvp_session_queue *sq; struct synx_session ssid; u32 in, out; + u32 hfi_err = HFI_ERR_NONE; + struct cvp_hfi_msg_session_hdr *hdr; - dprintk(CVP_DBG, "Enter %s\n", __func__); + dprintk(CVP_DBG, "%s %s\n", current->comm, __func__); hdev = inst->core->device; sq = &inst->session_queue_fence; @@ -1020,9 +1044,17 @@ static int cvp_fence_proc(struct msm_cvp_inst *inst, u32 *synx, if (h_synx) { rc = synx_wait(ssid, h_synx, timeout_ms); if (rc) { - dprintk(CVP_ERR, "%s: synx_wait %d failed\n", - __func__, i); - synx_state = SYNX_STATE_SIGNALED_ERROR; + synx_state = synx_get_status(ssid, h_synx); + if (synx_state == SYNX_STATE_SIGNALED_CANCEL) { + dprintk(CVP_DBG, + "%s: synx_wait %d cancel %d state %d\n", + current->comm, i, rc, synx_state); + } else { + dprintk(CVP_ERR, + "%s: synx_wait %d failed %d state %d\n", + current->comm, i, rc, synx_state); + synx_state = SYNX_STATE_SIGNALED_ERROR; + } goto exit; } } @@ -1032,14 +1064,32 @@ static int cvp_fence_proc(struct msm_cvp_inst *inst, u32 *synx, rc = call_hfi_op(hdev, session_send, (void *)inst->session, (struct cvp_kmd_hfi_packet *)pkt); if (rc) { - dprintk(CVP_ERR, "%s: Failed in call_hfi_op %d, %x\n", __func__, - pkt->size, pkt->packet_type); + dprintk(CVP_ERR, "%s %s: Failed in call_hfi_op %d, %x\n", + current->comm, __func__, pkt->size, pkt->packet_type); synx_state = SYNX_STATE_SIGNALED_ERROR; goto exit; } timeout = msecs_to_jiffies(CVP_MAX_WAIT_TIME); - rc = cvp_wait_process_message(inst, sq, &ktid, timeout, NULL); + rc = cvp_wait_process_message(inst, sq, &ktid, timeout, + (struct cvp_kmd_hfi_packet *)pkt); + hdr = (struct cvp_hfi_msg_session_hdr *)pkt; + hfi_err = hdr->error_type; + if (rc) { + dprintk(CVP_ERR, "%s %s: cvp_wait_process_message rc %d\n", + current->comm, __func__, rc); + synx_state = SYNX_STATE_SIGNALED_ERROR; + goto exit; + } + if (hfi_err == HFI_ERR_SESSION_FLUSHED) { + dprintk(CVP_DBG, "%s %s: cvp_wait_process_message flushed\n", + current->comm, __func__); + synx_state = SYNX_STATE_SIGNALED_CANCEL; + } else if (hfi_err != HFI_ERR_NONE) { + dprintk(CVP_ERR, "%s %s: cvp_wait_process_message hfi err %d\n", + current->comm, __func__, hfi_err); + synx_state = SYNX_STATE_SIGNALED_CANCEL; + } exit: i = in + 1; @@ -1049,7 +1099,7 @@ exit: rc = synx_signal(ssid, h_synx, synx_state); if (rc) { dprintk(CVP_ERR, "%s: synx_signal %d failed\n", - __func__, i); + current->comm, i); synx_state = SYNX_STATE_SIGNALED_ERROR; } } @@ -1102,7 +1152,7 @@ static int cvp_import_synx(struct msm_cvp_inst *inst, u32 type, u32 *fence, switch (type) { case HFI_CMD_SESSION_CVP_DME_FRAME: { - start = 0; + start = 1; end = HFI_DME_BUF_NUM; break; } @@ -1204,9 +1254,10 @@ static int cvp_fence_thread(void *data) struct msm_cvp_inst *inst; struct cvp_fence_queue *q; enum queue_state state; - struct cvp_fence_command *fence_data; + struct cvp_fence_command *f; struct cvp_hfi_cmd_session_hdr *pkt; u32 *synx; + u64 ktid; dprintk(CVP_DBG, "Enter %s\n", current->comm); @@ -1222,20 +1273,22 @@ static int cvp_fence_thread(void *data) wait: dprintk(CVP_DBG, "%s starts wait\n", current->comm); - fence_data = NULL; - wait_event_interruptible(q->wq, cvp_fence_wait(q, &fence_data, &state)); + f = NULL; + wait_event_interruptible(q->wq, cvp_fence_wait(q, &f, &state)); if (state != QUEUE_ACTIVE) goto exit; - if (!fence_data) + if (!f) goto wait; - pkt = fence_data->pkt; - synx = (u32 *)fence_data->synx; + pkt = f->pkt; + synx = (u32 *)f->synx; - dprintk(CVP_DBG, "%s starts work\n", current->comm); + ktid = pkt->client_data.kdata & (FENCE_BIT - 1); + dprintk(CVP_DBG, "%s starts working on frame %llu frameID %llu\n", + current->comm, ktid, f->frame_id); - switch (fence_data->type) { + switch (f->type) { case HFI_CMD_SESSION_CVP_DME_FRAME: rc = cvp_fence_dme(inst, synx, pkt); break; @@ -1244,18 +1297,24 @@ wait: break; default: dprintk(CVP_ERR, "%s: unknown hfi cmd type 0x%x\n", - __func__, fence_data->type); + __func__, f->type); rc = -EINVAL; goto exit; break; } - cvp_release_synx(inst, fence_data->type, synx); - spin_lock(&q->lock); - list_del_init(&fence_data->list); - spin_unlock(&q->lock); - cvp_free_fence_data(fence_data); + mutex_lock(&q->lock); + cvp_release_synx(inst, f->type, synx); + list_del_init(&f->list); + mutex_unlock(&q->lock); + + dprintk(CVP_DBG, "%s is done with frame %llu frameID %llu\n", + current->comm, ktid, f->frame_id); + + cvp_free_fence_data(f); + goto wait; + exit: dprintk(CVP_DBG, "%s exit\n", current->comm); cvp_put_inst(inst); @@ -1271,9 +1330,10 @@ static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, struct cvp_hfi_cmd_session_hdr *pkt; unsigned int offset, buf_num, in_offset, in_buf_num; struct msm_cvp_inst *s; - struct cvp_fence_command *fcmd; + struct cvp_fence_command *f; struct cvp_fence_queue *q; u32 *fence; + enum op_mode mode; if (!inst || !inst->core || !arg || !inst->core->device) { dprintk(CVP_ERR, "%s: invalid params\n", __func__); @@ -1284,6 +1344,18 @@ static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, if (!s) return -ECONNRESET; + q = &inst->fence_cmd_queue; + + mutex_lock(&q->lock); + mode = q->mode; + mutex_unlock(&q->lock); + + if (mode == OP_DRAINING) { + dprintk(CVP_DBG, "%s: flush in progress\n", __func__); + rc = -EBUSY; + goto exit; + } + in_offset = arg->buf_offset; in_buf_num = arg->buf_num; @@ -1311,24 +1383,29 @@ static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, if (rc) goto exit; - rc = cvp_alloc_fence_data(&fcmd, pkt->size); + rc = cvp_alloc_fence_data(&f, pkt->size); if (rc) goto exit; - fcmd->type = cvp_hfi_defs[idx].type; - memcpy(fcmd->pkt, pkt, pkt->size); + f->type = cvp_hfi_defs[idx].type; + f->frame_id = arg->data.hfi_fence_pkt.frame_id; + f->mode = OP_NORMAL; - fcmd->pkt->client_data.kdata |= FENCE_BIT; + dprintk(CVP_DBG, "%s: frameID %llu\n", __func__, f->frame_id); - rc = cvp_import_synx(inst, fcmd->type, fence, fcmd->synx); + memcpy(f->pkt, pkt, pkt->size); + + f->pkt->client_data.kdata |= FENCE_BIT; + + rc = cvp_import_synx(inst, f->type, fence, f->synx); if (rc) { - kfree(fcmd); + kfree(f); goto exit; } - q = &inst->fence_cmd_queue; - spin_lock(&q->lock); - list_add_tail(&fcmd->list, &inst->fence_cmd_queue.wait_list); - spin_unlock(&q->lock); + + mutex_lock(&q->lock); + list_add_tail(&f->list, &inst->fence_cmd_queue.wait_list); + mutex_unlock(&q->lock); wake_up(&inst->fence_cmd_queue.wq); @@ -1840,9 +1917,9 @@ static int cvp_fence_thread_start(struct msm_cvp_inst *inst) return 0; q = &inst->fence_cmd_queue; - spin_lock(&q->lock); + mutex_lock(&q->lock); q->state = QUEUE_ACTIVE; - spin_unlock(&q->lock); + mutex_unlock(&q->lock); for (i = 0; i < inst->prop.fthread_nr; ++i) { if (!cvp_get_inst_validate(inst->core, inst)) { @@ -1866,9 +1943,9 @@ static int cvp_fence_thread_start(struct msm_cvp_inst *inst) exit: if (rc) { - spin_lock(&q->lock); + mutex_lock(&q->lock); q->state = QUEUE_STOP; - spin_unlock(&q->lock); + mutex_unlock(&q->lock); wake_up_all(&q->wq); } return rc; @@ -1884,9 +1961,9 @@ static int cvp_fence_thread_stop(struct msm_cvp_inst *inst) q = &inst->fence_cmd_queue; - spin_lock(&q->lock); + mutex_lock(&q->lock); q->state = QUEUE_STOP; - spin_unlock(&q->lock); + mutex_unlock(&q->lock); sq = &inst->session_queue_fence; spin_lock(&sq->lock); @@ -2102,10 +2179,221 @@ static int msm_cvp_set_sysprop(struct msm_cvp_inst *inst, return rc; } -static int msm_cvp_flush_all(struct msm_cvp_inst *inst) +static int cvp_cancel_input_synx(struct msm_cvp_inst *inst, u32 type, u32 *synx) +{ + int rc = 0; + int i; + int h_synx; + struct synx_session ssid; + int start = 0, end = 0; + int synx_state = SYNX_STATE_SIGNALED_CANCEL; + + ssid = inst->synx_session_id; + + switch (type) { + case HFI_CMD_SESSION_CVP_DME_FRAME: + { + start = 1; + end = HFI_DME_BUF_NUM - 1; + break; + } + case HFI_CMD_SESSION_CVP_FD_FRAME: + { + u32 in, out; + + in = synx[0] >> 16; + out = synx[0] & 0xFFFF; + + start = 1; + end = in + 1; + break; + } + default: + dprintk(CVP_ERR, "%s: unknown fence type\n", __func__); + rc = -EINVAL; + return rc; + } + + for (i = start; i < end; ++i) { + h_synx = synx[i]; + if (h_synx) { + rc = synx_signal(ssid, h_synx, synx_state); + if (rc && rc != -EALREADY) { + dprintk(CVP_ERR, "%s: synx_signal %d failed\n", + __func__, i); + synx_state = SYNX_STATE_SIGNALED_ERROR; + } + } + } + + return rc; +} + +static int cvp_cancel_output_synx(struct msm_cvp_inst *inst, u32 type, + u32 *synx) +{ + int rc = 0; + int i; + int h_synx; + struct synx_session ssid; + int start = 0, end = 0; + int synx_state = SYNX_STATE_SIGNALED_CANCEL; + + ssid = inst->synx_session_id; + + switch (type) { + case HFI_CMD_SESSION_CVP_DME_FRAME: + { + start = FENCE_DME_OUTPUT_IDX; + end = FENCE_DME_OUTPUT_IDX + 1; + break; + } + case HFI_CMD_SESSION_CVP_FD_FRAME: + { + u32 in, out; + + in = synx[0] >> 16; + out = synx[0] & 0xFFFF; + + start = in + 1; + end = in + out + 1; + break; + } + default: + dprintk(CVP_ERR, "%s: unknown fence type\n", __func__); + rc = -EINVAL; + return rc; + } + + for (i = start; i < end; ++i) { + h_synx = synx[i]; + if (h_synx) { + rc = synx_signal(ssid, h_synx, synx_state); + if (rc) { + dprintk(CVP_ERR, "%s: synx_signal %d failed\n", + __func__, i); + synx_state = SYNX_STATE_SIGNALED_ERROR; + } + } + } + + return rc; +} + +static int cvp_drain_fence_cmd_queue_partial(struct msm_cvp_inst *inst) +{ + unsigned long wait_time; + struct cvp_fence_queue *q; + struct cvp_fence_command *f; + int rc = 0; + int count = 0, max_count = 0; + + q = &inst->fence_cmd_queue; + + mutex_lock(&q->lock); + + list_for_each_entry(f, &q->sched_list, list) { + if (f->mode == OP_FLUSH) + continue; + ++count; + } + + list_for_each_entry(f, &q->wait_list, list) { + if (f->mode == OP_FLUSH) + continue; + ++count; + } + + mutex_unlock(&q->lock); + wait_time = count * CVP_MAX_WAIT_TIME * 1000; + + dprintk(CVP_DBG, "%s: wait %d us for %d fence command\n", + __func__, wait_time, count); + + count = 0; + max_count = wait_time / 100; + +retry: + mutex_lock(&q->lock); + f = list_first_entry(&q->sched_list, struct cvp_fence_command, list); + + /* Wait for all normal frames to finish before return */ + if ((f && f->mode == OP_FLUSH) || + (list_empty(&q->sched_list) && list_empty(&q->wait_list))) { + mutex_unlock(&q->lock); + return rc; + } + + mutex_unlock(&q->lock); + usleep_range(100, 200); + ++count; + if (count < max_count) { + goto retry; + } else { + rc = -ETIMEDOUT; + dprintk(CVP_ERR, "%s: timed out!\n", __func__); + } + + return rc; +} + +static int cvp_drain_fence_sched_list(struct msm_cvp_inst *inst) +{ + unsigned long wait_time; + struct cvp_fence_queue *q; + struct cvp_fence_command *f; + int rc = 0; + int count = 0, max_count = 0; + u64 ktid; + + q = &inst->fence_cmd_queue; + + mutex_lock(&q->lock); + list_for_each_entry(f, &q->sched_list, list) { + ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); + dprintk(CVP_DBG, "%s: frame %llu is in sched_list\n", + __func__, ktid); + dprintk(CVP_DBG, "%s: frameID %llu is in sched_list\n", + __func__, f->frame_id); + ++count; + } + mutex_unlock(&q->lock); + wait_time = count * CVP_MAX_WAIT_TIME * 1000; + + dprintk(CVP_DBG, "%s: wait %d us for %d fence command\n", + __func__, wait_time, count); + + count = 0; + max_count = wait_time / 100; + +retry: + mutex_lock(&q->lock); + if (list_empty(&q->sched_list)) { + mutex_unlock(&q->lock); + return rc; + } + + mutex_unlock(&q->lock); + usleep_range(100, 200); + ++count; + if (count < max_count) { + goto retry; + } else { + rc = -ETIMEDOUT; + dprintk(CVP_ERR, "%s: timed out!\n", __func__); + } + + return rc; +} + +static int cvp_flush_all(struct msm_cvp_inst *inst) { int rc = 0; struct msm_cvp_inst *s; + struct cvp_fence_queue *q; + struct cvp_fence_command *f, *d; + struct cvp_hfi_device *hdev; + u64 ktid; if (!inst || !inst->core) { dprintk(CVP_ERR, "%s: invalid params\n", __func__); @@ -2116,6 +2404,166 @@ static int msm_cvp_flush_all(struct msm_cvp_inst *inst) if (!s) return -ECONNRESET; + q = &inst->fence_cmd_queue; + hdev = inst->core->device; + + mutex_lock(&q->lock); + q->mode = OP_DRAINING; + + list_for_each_entry_safe(f, d, &q->wait_list, list) { + ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); + + dprintk(CVP_DBG, "%s: flush frame %llu from wait_list\n", + __func__, ktid); + dprintk(CVP_DBG, "%s: flush frameID %llu from wait_list\n", + __func__, f->frame_id); + + list_del_init(&f->list); + msm_cvp_unmap_frame(inst, f->pkt->client_data.kdata); + cvp_cancel_output_synx(inst, f->type, f->synx); + cvp_release_synx(inst, f->type, f->synx); + cvp_free_fence_data(f); + } + + list_for_each_entry(f, &q->sched_list, list) { + ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); + + dprintk(CVP_DBG, "%s: flush frame %llu from sched_list\n", + __func__, ktid); + dprintk(CVP_DBG, "%s: flush frameID %llu from sched_list\n", + __func__, f->frame_id); + cvp_cancel_input_synx(inst, f->type, f->synx); + } + + mutex_unlock(&q->lock); + + dprintk(CVP_DBG, "%s: send flush to fw\n", __func__); + + /* Send flush to FW */ + rc = call_hfi_op(hdev, session_flush, (void *)inst->session); + if (rc) { + dprintk(CVP_WARN, "%s: continue flush without fw. rc %d\n", + __func__, rc); + goto exit; + } + + /* Wait for FW response */ + rc = wait_for_sess_signal_receipt(inst, HAL_SESSION_FLUSH_DONE); + if (rc) + dprintk(CVP_WARN, "%s: wait for signal failed, rc %d\n", + __func__, rc); + + dprintk(CVP_DBG, "%s: received flush from fw\n", __func__); + +exit: + rc = cvp_drain_fence_sched_list(inst); + + mutex_lock(&q->lock); + q->mode = OP_NORMAL; + mutex_unlock(&q->lock); + + cvp_put_inst(s); + return rc; +} + +static void cvp_mark_fence_command(struct msm_cvp_inst *inst, u64 frame_id) +{ + int found = false; + struct cvp_fence_queue *q; + struct cvp_fence_command *f; + + q = &inst->fence_cmd_queue; + + list_for_each_entry(f, &q->sched_list, list) { + if (found) { + f->mode = OP_FLUSH; + continue; + } + + if (f->frame_id >= frame_id) { + found = true; + f->mode = OP_FLUSH; + } + } + + list_for_each_entry(f, &q->wait_list, list) { + if (found) { + f->mode = OP_FLUSH; + continue; + } + + if (f->frame_id >= frame_id) { + found = true; + f->mode = OP_FLUSH; + } + } +} + +static int cvp_flush_frame(struct msm_cvp_inst *inst, u64 frame_id) +{ + int rc = 0; + struct msm_cvp_inst *s; + struct cvp_fence_queue *q; + struct cvp_fence_command *f, *d; + u64 ktid; + + if (!inst || !inst->core) { + dprintk(CVP_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + s = cvp_get_inst_validate(inst->core, inst); + if (!s) + return -ECONNRESET; + + q = &inst->fence_cmd_queue; + + mutex_lock(&q->lock); + q->mode = OP_DRAINING; + + cvp_mark_fence_command(inst, frame_id); + + list_for_each_entry_safe(f, d, &q->wait_list, list) { + if (f->mode != OP_FLUSH) + continue; + + ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); + + dprintk(CVP_DBG, "%s: flush frame %llu from wait_list\n", + __func__, ktid); + dprintk(CVP_DBG, "%s: flush frameID %llu from wait_list\n", + __func__, f->frame_id); + + list_del_init(&f->list); + msm_cvp_unmap_frame(inst, f->pkt->client_data.kdata); + cvp_cancel_output_synx(inst, f->type, f->synx); + cvp_release_synx(inst, f->type, f->synx); + cvp_free_fence_data(f); + } + + list_for_each_entry(f, &q->sched_list, list) { + if (f->mode != OP_FLUSH) + continue; + + ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); + + dprintk(CVP_DBG, "%s: flush frame %llu from sched_list\n", + __func__, ktid); + dprintk(CVP_DBG, "%s: flush frameID %llu from sched_list\n", + __func__, f->frame_id); + cvp_cancel_input_synx(inst, f->type, f->synx); + } + + mutex_unlock(&q->lock); + + rc = cvp_drain_fence_cmd_queue_partial(inst); + if (rc) + dprintk(CVP_WARN, "%s: continue flush. rc %d\n", + __func__, rc); + + rc = cvp_flush_all(inst); + + cvp_put_inst(s); return rc; } @@ -2211,10 +2659,10 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) rc = msm_cvp_set_sysprop(inst, arg); break; case CVP_KMD_FLUSH_ALL: - rc = msm_cvp_flush_all(inst); + rc = cvp_flush_all(inst); break; case CVP_KMD_FLUSH_FRAME: - dprintk(CVP_DBG, "CVP_KMD_FLUSH_FRAME is not implemented\n"); + rc = cvp_flush_frame(inst, arg->data.frame_id); break; default: dprintk(CVP_DBG, "%s: unknown arg type %#x\n", @@ -2252,7 +2700,7 @@ int msm_cvp_session_deinit(struct msm_cvp_inst *inst) mutex_lock(&inst->frames.lock); list_for_each_entry_safe(frame, dummy1, &inst->frames.list, list) { list_del(&frame->list); - msm_cvp_unmap_buf_cpu(frame); + msm_cvp_unmap_frame_buf(frame); } mutex_unlock(&inst->frames.lock); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c index 4093960b3284..b659f2aa9026 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c @@ -520,7 +520,25 @@ static void handle_release_res_done(enum hal_command_response cmd, void *data) static void handle_session_flush(enum hal_command_response cmd, void *data) { - dprintk(CVP_WARN, "%s is not supported on CVP!\n", __func__); + struct msm_cvp_cb_cmd_done *response = data; + struct msm_cvp_inst *inst; + + if (!response) { + dprintk(CVP_ERR, + "Failed to get valid response for release resource\n"); + return; + } + + inst = cvp_get_inst(get_cvp_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(CVP_WARN, "%s:Got a response for an inactive session\n", + __func__); + return; + } + + signal_session_msg_receipt(cmd, inst); + cvp_put_inst(inst); } static void handle_session_error(enum hal_command_response cmd, void *data) diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index cb5bbe34a536..6a6b96675869 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -232,11 +232,12 @@ static int __init_session_queue(struct msm_cvp_inst *inst) static void __init_fence_queue(struct msm_cvp_inst *inst) { - spin_lock_init(&inst->fence_cmd_queue.lock); + mutex_init(&inst->fence_cmd_queue.lock); INIT_LIST_HEAD(&inst->fence_cmd_queue.wait_list); INIT_LIST_HEAD(&inst->fence_cmd_queue.sched_list); init_waitqueue_head(&inst->fence_cmd_queue.wq); inst->fence_cmd_queue.state = QUEUE_ACTIVE; + inst->fence_cmd_queue.mode = OP_NORMAL; spin_lock_init(&inst->session_queue_fence.lock); INIT_LIST_HEAD(&inst->session_queue_fence.msgs); @@ -245,7 +246,14 @@ static void __init_fence_queue(struct msm_cvp_inst *inst) inst->session_queue_fence.state = QUEUE_ACTIVE; } -static void _deinit_session_queue(struct msm_cvp_inst *inst) +static void __deinit_fence_queue(struct msm_cvp_inst *inst) +{ + mutex_destroy(&inst->fence_cmd_queue.lock); + inst->fence_cmd_queue.state = QUEUE_INVALID; + inst->fence_cmd_queue.mode = OP_INVALID; +} + +static void __deinit_session_queue(struct msm_cvp_inst *inst) { struct cvp_session_msg *msg, *tmpmsg; @@ -361,7 +369,7 @@ void *msm_cvp_open(int core_id, int session_type) return inst; fail_init: - _deinit_session_queue(inst); + __deinit_session_queue(inst); mutex_lock(&core->lock); list_del(&inst->list); mutex_unlock(&core->lock); @@ -417,7 +425,9 @@ int msm_cvp_destroy(struct msm_cvp_inst *inst) mutex_destroy(&inst->lock); msm_cvp_debugfs_deinit_inst(inst); - _deinit_session_queue(inst); + + __deinit_session_queue(inst); + __deinit_fence_queue(inst); synx_uninitialize(inst->synx_session_id); pr_info(CVP_DBG_TAG "Closed cvp instance: %pK session_id = %d\n", diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h index a9b666394d7d..3801d7497999 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h @@ -273,9 +273,17 @@ struct cvp_session_prop { u32 ddr_op_cache; }; +enum op_mode { + OP_NORMAL, + OP_DRAINING, + OP_FLUSH, + OP_INVALID, +}; + struct cvp_fence_queue { - spinlock_t lock; + struct mutex lock; enum queue_state state; + enum op_mode mode; struct list_head wait_list; wait_queue_head_t wq; struct list_head sched_list; @@ -359,6 +367,8 @@ struct cvp_fence_type { struct cvp_fence_command { struct list_head list; + u64 frame_id; + enum op_mode mode; u32 type; u32 synx[MAX_HFI_FENCE_SIZE/2]; struct cvp_hfi_cmd_session_hdr *pkt; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_ioctl.c b/drivers/media/platform/msm/cvp/msm_cvp_ioctl.c index 12e839cd7162..f014b36ba298 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_ioctl.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_ioctl.c @@ -78,7 +78,8 @@ static int _copy_fence_pkt_from_user(struct cvp_kmd_arg *kp, struct cvp_kmd_arg __user *up, unsigned int size) { - struct cvp_kmd_hfi_fence_packet *k, *u; + struct cvp_kmd_hfi_fence_packet *k; + struct cvp_kmd_hfi_fence_packet __user *u; int i; k = &kp->data.hfi_fence_pkt; @@ -91,6 +92,24 @@ static int _copy_fence_pkt_from_user(struct cvp_kmd_arg *kp, if (get_user(k->fence_data[i], &u->fence_data[i])) return -EFAULT; } + + if (get_user(k->frame_id, &u->frame_id)) { + dprintk(CVP_ERR, "Failed to get frame id from fence pkt\n"); + return -EFAULT; + } + + + return 0; +} + +static int _copy_frameid_from_user(struct cvp_kmd_arg *kp, + struct cvp_kmd_arg __user *up) +{ + if (get_user(kp->data.frame_id, &up->data.frame_id)) { + dprintk(CVP_ERR, "Failed to get frame id from user\n"); + return -EFAULT; + } + return 0; } @@ -211,6 +230,41 @@ static int _get_session_ctrl_from_user( return 0; } +static int _get_session_info_from_user( + struct cvp_kmd_session_info *k, + struct cvp_kmd_session_info __user *u) +{ + int i; + + if (get_user(k->session_id, &u->session_id)) + return -EFAULT; + + for (i = 0; i < 10; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + return 0; +} + +static int _get_power_request( + struct cvp_kmd_request_power *k, + struct cvp_kmd_request_power __user *u) +{ + int i; + + if (get_user(k->clock_cycles_a, &u->clock_cycles_a) || + get_user(k->clock_cycles_b, &u->clock_cycles_b) || + get_user(k->ddr_bw, &u->ddr_bw) || + get_user(k->sys_cache_bw, &u->sys_cache_bw)) + return -EFAULT; + + for (i = 0; i < 8; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + + return 0; + +} + static int convert_from_user(struct cvp_kmd_arg *kp, unsigned long arg, struct msm_cvp_inst *inst) @@ -238,31 +292,30 @@ static int convert_from_user(struct cvp_kmd_arg *kp, switch (kp->type) { case CVP_KMD_GET_SESSION_INFO: { - struct cvp_kmd_session_info *k, *u; + struct cvp_kmd_session_info *k; + struct cvp_kmd_session_info __user *u; k = &kp->data.session; u = &up->data.session; - if (get_user(k->session_id, &u->session_id)) + if (_get_session_info_from_user(k, u)) { + dprintk(CVP_ERR, "fail to get sess info\n"); return -EFAULT; - for (i = 0; i < 10; i++) - if (get_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; + } + break; } case CVP_KMD_REQUEST_POWER: { - struct cvp_kmd_request_power *k, *u; + struct cvp_kmd_request_power *k; + struct cvp_kmd_request_power __user *u; k = &kp->data.req_power; u = &up->data.req_power; - if (get_user(k->clock_cycles_a, &u->clock_cycles_a) || - get_user(k->clock_cycles_b, &u->clock_cycles_b) || - get_user(k->ddr_bw, &u->ddr_bw) || - get_user(k->sys_cache_bw, &u->sys_cache_bw)) + if (_get_power_request(k, u)) { + dprintk(CVP_ERR, "fail to get power request\n"); return -EFAULT; - for (i = 0; i < 8; i++) - if (get_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; + } + break; } case CVP_KMD_REGISTER_BUFFER: @@ -364,8 +417,15 @@ static int convert_from_user(struct cvp_kmd_arg *kp, } break; } + case CVP_KMD_FLUSH_ALL: case CVP_KMD_UPDATE_POWER: break; + case CVP_KMD_FLUSH_FRAME: + { + if (_copy_frameid_from_user(kp, up)) + return -EFAULT; + break; + } default: dprintk(CVP_ERR, "%s: unknown cmd type 0x%x\n", __func__, kp->type); @@ -376,6 +436,42 @@ static int convert_from_user(struct cvp_kmd_arg *kp, return rc; } +static int _put_user_session_info( + struct cvp_kmd_session_info *k, + struct cvp_kmd_session_info __user *u) +{ + int i; + + if (put_user(k->session_id, &u->session_id)) + return -EFAULT; + + for (i = 0; i < 10; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + + return 0; +} + + +static int _put_power_request( + struct cvp_kmd_request_power *k, + struct cvp_kmd_request_power __user *u) +{ + int i; + + if (put_user(k->clock_cycles_a, &u->clock_cycles_a) || + put_user(k->clock_cycles_b, &u->clock_cycles_b) || + put_user(k->ddr_bw, &u->ddr_bw) || + put_user(k->sys_cache_bw, &u->sys_cache_bw)) + return -EFAULT; + + for (i = 0; i < 8; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + + return 0; +} + static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) { int rc = 0; @@ -405,31 +501,30 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) } case CVP_KMD_GET_SESSION_INFO: { - struct cvp_kmd_session_info *k, *u; + struct cvp_kmd_session_info *k; + struct cvp_kmd_session_info __user *u; k = &kp->data.session; u = &up->data.session; - if (put_user(k->session_id, &u->session_id)) + if (_put_user_session_info(k, u)) { + dprintk(CVP_ERR, "fail to copy sess info to user\n"); return -EFAULT; - for (i = 0; i < 10; i++) - if (put_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; + } + break; } case CVP_KMD_REQUEST_POWER: { - struct cvp_kmd_request_power *k, *u; + struct cvp_kmd_request_power *k; + struct cvp_kmd_request_power __user *u; k = &kp->data.req_power; u = &up->data.req_power; - if (put_user(k->clock_cycles_a, &u->clock_cycles_a) || - put_user(k->clock_cycles_b, &u->clock_cycles_b) || - put_user(k->ddr_bw, &u->ddr_bw) || - put_user(k->sys_cache_bw, &u->sys_cache_bw)) + if (_put_power_request(k, u)) { + dprintk(CVP_ERR, "fail to copy power to user\n"); return -EFAULT; - for (i = 0; i < 8; i++) - if (put_user(k->reserved[i], &u->reserved[i])) - return -EFAULT; + } + break; } case CVP_KMD_REGISTER_BUFFER: @@ -508,8 +603,9 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) } break; } + case CVP_KMD_FLUSH_ALL: + case CVP_KMD_FLUSH_FRAME: case CVP_KMD_SET_SYS_PROPERTY: - break; case CVP_KMD_UPDATE_POWER: break; default: