From 8486a3deec1814acf8f89dbc8b6e854cc8a0f03c Mon Sep 17 00:00:00 2001 From: Xinhuang Li Date: Tue, 12 Dec 2017 15:30:48 +0800 Subject: [PATCH] driver: video: rockchip: fix the memory leak of the encoder 1.when release buffer should call vpu_iommu_clear function. 2.before call vpu_iommu_clear that we should call vpu_drm_unmap_iommu&vpu_drm_free if there is through vpu_drm_alloc to allocate buffer. Change-Id: I01e7fac88c6da40e8cb4ee2199dd38283323783b Signed-off-by: Xinhuang Li --- drivers/video/rockchip/vpu/mpp_dev_common.c | 8 +- drivers/video/rockchip/vpu/mpp_dev_common.h | 1 + drivers/video/rockchip/vpu/mpp_dev_h265e.c | 119 +++++++++++--------- drivers/video/rockchip/vpu/mpp_dev_rkvenc.c | 4 +- 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/drivers/video/rockchip/vpu/mpp_dev_common.c b/drivers/video/rockchip/vpu/mpp_dev_common.c index a4297c001c20..f322c811ebe4 100644 --- a/drivers/video/rockchip/vpu/mpp_dev_common.c +++ b/drivers/video/rockchip/vpu/mpp_dev_common.c @@ -687,14 +687,17 @@ static int mpp_dev_release(struct inode *inode, struct file *filp) } wake_up(&session->wait); + if (mpp->ops->release) + mpp->ops->release(session); mpp_srv_lock(mpp->srv); /* remove this filp from the asynchronusly notified filp's */ list_del_init(&session->list_session); mpp_dev_session_clear(mpp, session); + vpu_iommu_clear(mpp->iommu_info, session); filp->private_data = NULL; mpp_srv_unlock(mpp->srv); - if (mpp->ops->release) - mpp->ops->release(session); + if (mpp->ops->free) + mpp->ops->free(session); else kfree(session); @@ -1054,7 +1057,6 @@ static struct platform_driver mpp_dev_driver = { .remove = mpp_dev_remove, .driver = { .name = "mpp_dev", - .owner = THIS_MODULE, #if defined(CONFIG_OF) .of_match_table = of_match_ptr(mpp_dev_dt_ids), #endif diff --git a/drivers/video/rockchip/vpu/mpp_dev_common.h b/drivers/video/rockchip/vpu/mpp_dev_common.h index 466467c23e60..d4d1897b7ac3 100644 --- a/drivers/video/rockchip/vpu/mpp_dev_common.h +++ b/drivers/video/rockchip/vpu/mpp_dev_common.h @@ -244,6 +244,7 @@ struct mpp_dev_ops { unsigned int cmd, unsigned long arg); struct mpp_session *(*open)(struct rockchip_mpp_dev *mpp); void (*release)(struct mpp_session *session); + void (*free)(struct mpp_session *session); }; void mpp_dump_reg(void __iomem *regs, int count); diff --git a/drivers/video/rockchip/vpu/mpp_dev_h265e.c b/drivers/video/rockchip/vpu/mpp_dev_h265e.c index 8666a2277042..4667de83ef87 100644 --- a/drivers/video/rockchip/vpu/mpp_dev_h265e.c +++ b/drivers/video/rockchip/vpu/mpp_dev_h265e.c @@ -64,8 +64,10 @@ static ktime_t h265e_now, h265e_last; static struct mpp_session *rockchip_mpp_h265e_open(struct rockchip_mpp_dev *mpp); +static void rockchip_mpp_h265e_free(struct mpp_session *isession); static void rockchip_mpp_h265e_release(struct mpp_session *isession); -static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp); +static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp, + struct mpp_session *session); static int rockchip_mpp_h265e_encode_one_frame(struct rockchip_mpp_dev *mpp, struct h265e_ctx *ctx, int index); @@ -79,6 +81,16 @@ int rockchip_mpp_h265e_register_frame_buffer(struct rockchip_mpp_dev *mpp, static void rockchip_mpp_h265e_enable_clk(struct rockchip_mpp_dev *mpp); static void rockchip_mpp_h265e_disable_clk(struct rockchip_mpp_dev *mpp); +static void rockchip_mpp_h265e_dma_free(struct rockchip_mpp_dev *mpp, + struct mpp_session *session, + int hdl) +{ + if (hdl >= 0) { + vpu_iommu_unmap_iommu(mpp->iommu_info, session, hdl); + vpu_iommu_free(mpp->iommu_info, session, hdl); + } +} + static int rockchip_mpp_h265e_dma_alloc(struct rockchip_mpp_dev *mpp, struct mpp_session *session, size_t len, @@ -108,18 +120,6 @@ FAIL: return -1; } -static int rockchip_mpp_h265e_global_dma_alloc(struct rockchip_mpp_dev *mpp, - size_t len, - size_t align, - unsigned long *addr) -{ - struct mpp_session *session = list_first_entry(&mpp->srv->session, - struct mpp_session, - list_session); - - return rockchip_mpp_h265e_dma_alloc(mpp, session, len, align, addr); -} - static void rockchip_mpp_h265e_free_frame_buffer(struct rockchip_mpp_dev *mpp, struct rockchip_h265e_instance *instance) { @@ -130,22 +130,18 @@ static void rockchip_mpp_h265e_free_frame_buffer(struct rockchip_mpp_dev *mpp, mpp_debug_enter(); buf = &instance->mv; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); buf = &instance->fbc_luma; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); buf = &instance->fbc_chroma; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); buf = &instance->sub_sample; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); + for (i = 0; i < ARRAY_SIZE(instance->frame_buffer); i++) { fb = &instance->frame_buffer[i]; buf = &fb->buffer; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); fb->y = 0; fb->cb = 0; fb->cr = 0; @@ -170,8 +166,7 @@ static void rockchip_mpp_h265e_free_instance(struct rockchip_mpp_dev *mpp, #endif if (!mpp || !instance) return; - if (buf->hdl >= 0) - vpu_iommu_free(mpp->iommu_info, session, buf->hdl); + rockchip_mpp_h265e_dma_free(mpp, session, buf->hdl); rockchip_mpp_h265e_free_frame_buffer(mpp, instance); atomic_set(&enc->instance[index].is_used, 0); mpp_debug_leave(); @@ -252,7 +247,8 @@ static int rockchip_mpp_h265e_write_encoder_file(struct rockchip_mpp_dev *mpp) } #endif -static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp) +static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp, + struct mpp_session *session) { const struct firmware *firmware; u32 size = 0; @@ -260,9 +256,6 @@ static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp) container_of(mpp, struct rockchip_h265e_dev, dev); - struct mpp_session *session = list_first_entry(&mpp->srv->session, - struct mpp_session, - list_session); if (request_firmware(&firmware, H265E_FIRMWARE_NAME, mpp->dev) < 0) { mpp_err("firmware request failed\n"); @@ -273,10 +266,11 @@ static int rockchip_mpp_h265e_load_firmware(struct rockchip_mpp_dev *mpp) firmware->data, firmware->size); size = ALIGN(firmware->size, H265E_CODE_BUFFER_SIZE); enc->firmware.hdl = - rockchip_mpp_h265e_global_dma_alloc(mpp, - size, - MPP_ALIGN_SIZE, - &enc->firmware.dma_addr); + rockchip_mpp_h265e_dma_alloc(mpp, + session, + size, + MPP_ALIGN_SIZE, + &enc->firmware.dma_addr); if (enc->firmware.hdl < 0) { mpp_err("error: alloc firmware buffer error\n"); goto FAIL; @@ -1340,7 +1334,7 @@ int rockchip_mpp_h265e_register_frame_buffer(struct rockchip_mpp_dev *mpp, stride; mpp_write(mpp, value, H265E_COMMON_PIC_INFO); - memset(&instance->frame_buffer, 0, sizeof(instance->frame_buffer)); + memset(&instance->frame_buffer, -1, sizeof(instance->frame_buffer)); /* set frame buffer address*/ for (i = 0; i < count; i++) { frame_buffer = &instance->frame_buffer[i]; @@ -1766,6 +1760,7 @@ struct mpp_dev_ops h265e_ops = { .ioctl = rockchip_mpp_h265e_ioctl, .open = rockchip_mpp_h265e_open, .release = rockchip_mpp_h265e_release, + .free = rockchip_mpp_h265e_free, }; static void rockchip_mpp_h265e_enable_clk(struct rockchip_mpp_dev *mpp) @@ -1843,31 +1838,17 @@ static struct mpp_session *rockchip_mpp_h265e_open(struct rockchip_mpp_dev *mpp) #endif mpp_dev_power_on(mpp); - if (!atomic_read(&enc->load_firmware)) { - ret = rockchip_mpp_h265e_load_firmware(mpp); - if (ret) - goto NFREE_FAIL; - atomic_inc(&enc->load_firmware); - enc->temp.size = H265E_TEMP_BUFFER_SIZE; - enc->temp.hdl = - rockchip_mpp_h265e_global_dma_alloc(mpp, - enc->temp.size, - MPP_ALIGN_SIZE, - &enc->temp.dma_addr); - if (enc->temp.hdl < 0) { - mpp_err("error: alloc temp buffer error\n"); - goto NFREE_FAIL; - } - } for (i = 0; i < H265E_INSTANCE_NUM; i++) { instance = &enc->instance[i]; + instance->session = &session->isession; if (!atomic_read(&instance->is_used)) { instance->work.size = H265E_WORK_BUFFER_SIZE; instance->work.hdl = - rockchip_mpp_h265e_global_dma_alloc(mpp, - instance->work.size, - MPP_ALIGN_SIZE, - &instance->work.dma_addr); + rockchip_mpp_h265e_dma_alloc(mpp, + instance->session, + instance->work.size, + MPP_ALIGN_SIZE, + &instance->work.dma_addr); instance->index = i; atomic_set(&instance->is_used, 1); break; @@ -1877,11 +1858,29 @@ static struct mpp_session *rockchip_mpp_h265e_open(struct rockchip_mpp_dev *mpp) mpp_err("error: the num of instance up to H265E_INSTANCE_NUM\n"); goto NFREE_FAIL; } + + if (!atomic_read(&enc->load_firmware)) { + ret = rockchip_mpp_h265e_load_firmware(mpp, instance->session); + if (ret) + goto FAIL; + atomic_inc(&enc->load_firmware); + enc->temp.size = H265E_TEMP_BUFFER_SIZE; + enc->temp.hdl = + rockchip_mpp_h265e_dma_alloc(mpp, + instance->session, + enc->temp.size, + MPP_ALIGN_SIZE, + &enc->temp.dma_addr); + if (enc->temp.hdl < 0) { + mpp_err("error: alloc temp buffer error\n"); + goto FAIL; + } + } + index = instance->index; instance->status = H265E_INSTANCE_STATUS_ERROR; mpp_debug(DEBUG_H265E_INFO, "%s = %d\n", __func__, index); - instance->session = &session->isession; session->instance_index = index; code_base = (u32)enc->firmware.dma_addr; mpp_debug(DEBUG_H265E_INFO, "h265e code_base = %x\n", code_base); @@ -1980,6 +1979,15 @@ NFREE_FAIL: return NULL; } +static void rockchip_mpp_h265e_free(struct mpp_session *isession) +{ + struct h265e_session *session = + container_of(isession, + struct h265e_session, + isession); + kfree(session); +} + static void rockchip_mpp_h265e_release(struct mpp_session *isession) { struct h265e_session *session = @@ -2006,7 +2014,6 @@ static void rockchip_mpp_h265e_release(struct mpp_session *isession) if (mpp_read(mpp, H265E_RET_SUCCESS) == 0) mpp_err("h265e close instance %d ret fail\n", index); rockchip_mpp_h265e_free_instance(mpp, index); - kfree(session); #if H265E_POWER_SAVE rockchip_mpp_h265e_disable_clk(mpp); #endif diff --git a/drivers/video/rockchip/vpu/mpp_dev_rkvenc.c b/drivers/video/rockchip/vpu/mpp_dev_rkvenc.c index 9b0046369688..3369aba736d2 100644 --- a/drivers/video/rockchip/vpu/mpp_dev_rkvenc.c +++ b/drivers/video/rockchip/vpu/mpp_dev_rkvenc.c @@ -636,7 +636,7 @@ static struct mpp_session *mpp_dev_rkvenc_open(struct rockchip_mpp_dev *mpp) return &session->isession; } -static void mpp_dev_rkvenc_release(struct mpp_session *isession) +static void mpp_dev_rkvenc_free(struct mpp_session *isession) { struct rkvenc_session *session = to_rkvenc_session(isession); @@ -652,7 +652,7 @@ struct mpp_dev_ops rkvenc_ops = { .result = rockchip_mpp_rkvenc_result, .ioctl = rockchip_mpp_rkvenc_ioctl, .open = mpp_dev_rkvenc_open, - .release = mpp_dev_rkvenc_release, + .free = mpp_dev_rkvenc_free, }; static void rockchip_mpp_rkvenc_power_on(struct rockchip_mpp_dev *mpp)