diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 72edfa6dbaf3..ef64fea4fabe 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -964,8 +964,7 @@ static int mpp_process_request(struct mpp_session *session, if (!mpp) return -EINVAL; session->device_type = (enum MPP_DEVICE_TYPE)client_type; - session->dma = mpp_dma_session_create(mpp->dev); - session->dma->max_buffers = mpp->session_max_buffers; + session->dma = mpp_dma_session_create(mpp->dev, mpp->session_max_buffers); session->mpp = mpp; session->index = atomic_fetch_inc(&mpp->session_index); if (mpp->dev_ops->init_session) { diff --git a/drivers/video/rockchip/mpp/mpp_iommu.c b/drivers/video/rockchip/mpp/mpp_iommu.c index d123f42da7e6..740441ff8302 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.c +++ b/drivers/video/rockchip/mpp/mpp_iommu.c @@ -38,7 +38,7 @@ mpp_dma_find_buffer_fd(struct mpp_dma_session *dma, int fd) mutex_lock(&dma->list_mutex); list_for_each_entry_safe(buffer, n, - &dma->buffer_list, link) { + &dma->used_list, link) { /* * fd may dup several and point the same dambuf. * thus, here should be distinguish with the dmabuf. @@ -61,12 +61,11 @@ static void mpp_dma_release_buffer(struct kref *ref) container_of(ref, struct mpp_dma_buffer, ref); buffer->dma->buffer_count--; - list_del_init(&buffer->link); + list_move_tail(&buffer->link, &buffer->dma->unused_list); dma_buf_unmap_attachment(buffer->attach, buffer->sgt, buffer->dir); dma_buf_detach(buffer->dmabuf, buffer->attach); dma_buf_put(buffer->dmabuf); - kfree(buffer); } /* Remove the oldest buffer when count more than the setting */ @@ -80,7 +79,7 @@ mpp_dma_remove_extra_buffer(struct mpp_dma_session *dma) if (dma->buffer_count > dma->max_buffers) { mutex_lock(&dma->list_mutex); list_for_each_entry_safe(buffer, n, - &dma->buffer_list, + &dma->used_list, link) { if (ktime_to_ns(oldest_time) == 0 || ktime_after(oldest_time, buffer->last_used)) { @@ -198,11 +197,17 @@ struct mpp_dma_buffer *mpp_dma_import_fd(struct mpp_iommu_info *iommu_info, return NULL; } /* A new DMA buffer */ - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + mutex_lock(&dma->list_mutex); + buffer = list_first_entry_or_null(&dma->unused_list, + struct mpp_dma_buffer, + link); if (!buffer) { ret = -ENOMEM; + mutex_unlock(&dma->list_mutex); goto fail; } + list_del_init(&buffer->link); + mutex_unlock(&dma->list_mutex); buffer->dmabuf = dmabuf; buffer->dir = DMA_BIDIRECTIONAL; @@ -230,11 +235,10 @@ struct mpp_dma_buffer *mpp_dma_import_fd(struct mpp_iommu_info *iommu_info, kref_init(&buffer->ref); /* Increase the reference for used outside the buffer pool */ kref_get(&buffer->ref); - INIT_LIST_HEAD(&buffer->link); mutex_lock(&dma->list_mutex); dma->buffer_count++; - list_add_tail(&buffer->link, &dma->buffer_list); + list_add_tail(&buffer->link, &dma->used_list); mutex_unlock(&dma->list_mutex); return buffer; @@ -242,7 +246,9 @@ struct mpp_dma_buffer *mpp_dma_import_fd(struct mpp_iommu_info *iommu_info, fail_map: dma_buf_detach(buffer->dmabuf, attach); fail_attach: - kfree(buffer); + mutex_lock(&dma->list_mutex); + list_add_tail(&buffer->link, &dma->unused_list); + mutex_unlock(&dma->list_mutex); fail: dma_buf_put(dmabuf); return ERR_PTR(ret); @@ -309,7 +315,7 @@ int mpp_dma_session_destroy(struct mpp_dma_session *dma) mutex_lock(&dma->list_mutex); list_for_each_entry_safe(buffer, n, - &dma->buffer_list, + &dma->used_list, link) { kref_put(&buffer->ref, mpp_dma_release_buffer); } @@ -321,17 +327,34 @@ int mpp_dma_session_destroy(struct mpp_dma_session *dma) } struct mpp_dma_session * -mpp_dma_session_create(struct device *dev) +mpp_dma_session_create(struct device *dev, u32 max_buffers) { + int i; struct mpp_dma_session *dma = NULL; + struct mpp_dma_buffer *buffer = NULL; dma = kzalloc(sizeof(*dma), GFP_KERNEL); if (!dma) - return dma; + return NULL; - INIT_LIST_HEAD(&dma->buffer_list); mutex_init(&dma->list_mutex); + INIT_LIST_HEAD(&dma->unused_list); + INIT_LIST_HEAD(&dma->used_list); + if (max_buffers > MPP_SESSION_MAX_BUFFERS) { + mpp_debug(DEBUG_IOCTL, "session_max_buffer %d must less than %d\n", + max_buffers, MPP_SESSION_MAX_BUFFERS); + dma->max_buffers = MPP_SESSION_MAX_BUFFERS; + } else { + dma->max_buffers = max_buffers; + } + + for (i = 0; i < ARRAY_SIZE(dma->dma_bufs); i++) { + buffer = &dma->dma_bufs[i]; + buffer->dma = dma; + INIT_LIST_HEAD(&buffer->link); + list_add_tail(&buffer->link, &dma->unused_list); + } dma->dev = dev; return dma; diff --git a/drivers/video/rockchip/mpp/mpp_iommu.h b/drivers/video/rockchip/mpp/mpp_iommu.h index 9663ce9bf612..7a8b1b1279e2 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu.h +++ b/drivers/video/rockchip/mpp/mpp_iommu.h @@ -37,9 +37,13 @@ struct mpp_dma_buffer { struct device *dev; }; +#define MPP_SESSION_MAX_BUFFERS 60 + struct mpp_dma_session { /* the buffer used in session */ - struct list_head buffer_list; + struct list_head unused_list; + struct list_head used_list; + struct mpp_dma_buffer dma_bufs[MPP_SESSION_MAX_BUFFERS]; /* the mutex for the above buffer list */ struct mutex list_mutex; /* the max buffer num for the buffer list */ @@ -72,7 +76,7 @@ struct mpp_iommu_info { }; struct mpp_dma_session * -mpp_dma_session_create(struct device *dev); +mpp_dma_session_create(struct device *dev, u32 max_buffers); int mpp_dma_session_destroy(struct mpp_dma_session *dma); struct mpp_dma_buffer *