diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index bc21633cad..acb4dc3825 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -131,6 +131,7 @@ struct msm_vidc_inst { struct workqueue_struct *response_workq; struct list_head response_works; /* list of struct response_work */ struct list_head enc_input_crs; + struct list_head dmabuf_tracker; /* list of struct msm_memory_dmabuf */ bool once_per_session_set; bool ipsc_properties_set; bool opsc_properties_set; diff --git a/driver/vidc/inc/msm_vidc_memory.h b/driver/vidc/inc/msm_vidc_memory.h index 04eef96d56..3bfc4e934b 100644 --- a/driver/vidc/inc/msm_vidc_memory.h +++ b/driver/vidc/inc/msm_vidc_memory.h @@ -11,11 +11,18 @@ struct msm_vidc_core; struct msm_vidc_inst; +struct msm_memory_dmabuf { + struct list_head list; + struct dma_buf *dmabuf; + u32 refcount; +}; + enum msm_memory_pool_type { MSM_MEM_POOL_BUFFER = 0, MSM_MEM_POOL_MAP, MSM_MEM_POOL_ALLOC, MSM_MEM_POOL_TIMESTAMP, + MSM_MEM_POOL_DMABUF, MSM_MEM_POOL_MAX, }; @@ -40,8 +47,12 @@ int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map); int msm_vidc_memory_unmap(struct msm_vidc_core *core, struct msm_vidc_map *map); -struct dma_buf *msm_vidc_memory_get_dmabuf(int fd); -void msm_vidc_memory_put_dmabuf(void *dmabuf); +struct dma_buf *msm_vidc_memory_get_dmabuf(struct msm_vidc_inst *inst, + int fd); +void msm_vidc_memory_put_dmabuf(struct msm_vidc_inst *inst, + struct dma_buf *dmabuf); +void msm_vidc_memory_put_dmabuf_completely(struct msm_vidc_inst *inst, + struct msm_memory_dmabuf *buf); int msm_memory_pools_init(struct msm_vidc_inst *inst); void msm_memory_pools_deinit(struct msm_vidc_inst *inst); void *msm_memory_alloc(struct msm_vidc_inst *inst, diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index 93c5b4b9af..5f332bb29d 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -841,6 +841,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) INIT_LIST_HEAD(&inst->children.list); INIT_LIST_HEAD(&inst->firmware.list); INIT_LIST_HEAD(&inst->enc_input_crs); + INIT_LIST_HEAD(&inst->dmabuf_tracker); for (i = 0; i < MAX_SIGNAL; i++) init_completion(&inst->completions[i]); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 4dabe7dc43..98dd909f3b 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -2008,7 +2008,7 @@ int msm_vidc_memory_unmap_completely(struct msm_vidc_inst *inst, if (rc) break; if (!map->refcount) { - msm_vidc_memory_put_dmabuf(map->dmabuf); + msm_vidc_memory_put_dmabuf(inst, map->dmabuf); list_del(&map->list); msm_memory_free(inst, MSM_MEM_POOL_MAP, map); break; @@ -2266,7 +2266,7 @@ int msm_vidc_put_delayed_unmap(struct msm_vidc_inst *inst, struct msm_vidc_map * i_vpr_e(inst, "%s: unmap failed\n", __func__); if (!map->refcount) { - msm_vidc_memory_put_dmabuf(map->dmabuf); + msm_vidc_memory_put_dmabuf(inst, map->dmabuf); list_del(&map->list); msm_memory_free(inst, MSM_MEM_POOL_MAP, map); } @@ -2334,7 +2334,7 @@ int msm_vidc_unmap_driver_buf(struct msm_vidc_inst *inst, /* finally delete if refcount is zero */ if (!map->refcount) { - msm_vidc_memory_put_dmabuf(map->dmabuf); + msm_vidc_memory_put_dmabuf(inst, map->dmabuf); list_del(&map->list); msm_memory_free(inst, MSM_MEM_POOL_MAP, map); } @@ -2378,7 +2378,7 @@ int msm_vidc_map_driver_buf(struct msm_vidc_inst *inst, } INIT_LIST_HEAD(&map->list); map->type = buf->type; - map->dmabuf = msm_vidc_memory_get_dmabuf(buf->fd); + map->dmabuf = msm_vidc_memory_get_dmabuf(inst, buf->fd); if (!map->dmabuf) return -EINVAL; map->region = msm_vidc_get_buffer_region(inst, buf->type, __func__); @@ -2386,7 +2386,7 @@ int msm_vidc_map_driver_buf(struct msm_vidc_inst *inst, if (is_decode_session(inst) && is_output_buffer(buf->type)) { rc = msm_vidc_get_delayed_unmap(inst, map); if (rc) { - msm_vidc_memory_put_dmabuf(map->dmabuf); + msm_vidc_memory_put_dmabuf(inst, map->dmabuf); msm_memory_free(inst, MSM_MEM_POOL_MAP, map); return rc; } @@ -2414,7 +2414,7 @@ int msm_vidc_put_driver_buf(struct msm_vidc_inst *inst, msm_vidc_unmap_driver_buf(inst, buf); - msm_vidc_memory_put_dmabuf(buf->dmabuf); + msm_vidc_memory_put_dmabuf(inst, buf->dmabuf); /* delete the buffer from buffers->list */ list_del(&buf->list); @@ -2456,7 +2456,7 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, if (rc) goto error; - buf->dmabuf = msm_vidc_memory_get_dmabuf(buf->fd); + buf->dmabuf = msm_vidc_memory_get_dmabuf(inst, buf->fd); if (!buf->dmabuf) goto error; @@ -2470,7 +2470,7 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, return buf; error: - msm_vidc_memory_put_dmabuf(buf->dmabuf); + msm_vidc_memory_put_dmabuf(inst, buf->dmabuf); list_del(&buf->list); msm_memory_free(inst, MSM_MEM_POOL_BUFFER, buf); return NULL; @@ -4545,6 +4545,7 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buf, *dummy; struct msm_vidc_timestamp *ts, *dummy_ts; + struct msm_memory_dmabuf *dbuf, *dummy_dbuf; struct response_work *work, *dummy_work = NULL; static const enum msm_vidc_buffer_type ext_buf_types[] = { MSM_VIDC_BUF_INPUT, @@ -4614,6 +4615,12 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) msm_memory_free(inst, MSM_MEM_POOL_TIMESTAMP, ts); } + list_for_each_entry_safe(dbuf, dummy_dbuf, &inst->dmabuf_tracker, list) { + i_vpr_e(inst, "%s: removing dma_buf %#x, refcount %u\n", + __func__, dbuf->dmabuf, dbuf->refcount); + msm_vidc_memory_put_dmabuf_completely(inst, dbuf); + } + list_for_each_entry_safe(work, dummy_work, &inst->response_works, list) { list_del(&work->list); kfree(work->data); diff --git a/driver/vidc/src/msm_vidc_memory.c b/driver/vidc/src/msm_vidc_memory.c index bf18aba39b..17f3a558c3 100644 --- a/driver/vidc/src/msm_vidc_memory.c +++ b/driver/vidc/src/msm_vidc_memory.c @@ -60,28 +60,116 @@ exit: return NULL; } -struct dma_buf *msm_vidc_memory_get_dmabuf(int fd) +struct dma_buf *msm_vidc_memory_get_dmabuf(struct msm_vidc_inst *inst, int fd) { - struct dma_buf *dmabuf; + struct msm_memory_dmabuf *buf = NULL; + struct dma_buf *dmabuf = NULL; + bool found = false; + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + /* get local dmabuf ref for tracking */ dmabuf = dma_buf_get(fd); if (IS_ERR_OR_NULL(dmabuf)) { d_vpr_e("Failed to get dmabuf for %d, error %ld\n", fd, PTR_ERR(dmabuf)); - dmabuf = NULL; + return NULL; } + /* track dmabuf - inc refcount if already present */ + list_for_each_entry(buf, &inst->dmabuf_tracker, list) { + if (buf->dmabuf == dmabuf) { + buf->refcount++; + found = true; + break; + } + } + if (found) { + /* put local dmabuf ref */ + dma_buf_put(dmabuf); + return dmabuf; + } + + /* get tracker instance from pool */ + buf = msm_memory_alloc(inst, MSM_MEM_POOL_DMABUF); + if (!buf) { + i_vpr_e(inst, "%s: dmabuf alloc failed\n", __func__); + dma_buf_put(dmabuf); + return NULL; + } + /* hold dmabuf strong ref in tracker */ + buf->dmabuf = dmabuf; + buf->refcount = 1; + INIT_LIST_HEAD(&buf->list); + + /* add new dmabuf entry to tracker */ + list_add_tail(&buf->list, &inst->dmabuf_tracker); + return dmabuf; } -void msm_vidc_memory_put_dmabuf(void *dmabuf) +void msm_vidc_memory_put_dmabuf(struct msm_vidc_inst *inst, struct dma_buf *dmabuf) { - if (!dmabuf) { - d_vpr_e("%s: NULL dmabuf\n", __func__); + struct msm_memory_dmabuf *buf = NULL; + bool found = false; + + if (!inst || !dmabuf) { + d_vpr_e("%s: invalid params\n", __func__); return; } - dma_buf_put((struct dma_buf *)dmabuf); + /* track dmabuf - dec refcount if already present */ + list_for_each_entry(buf, &inst->dmabuf_tracker, list) { + if (buf->dmabuf == dmabuf) { + buf->refcount--; + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid dmabuf %#x\n", __func__, dmabuf); + return; + } + + /* non-zero refcount - do nothing */ + if (buf->refcount) + return; + + /* remove dmabuf entry from tracker */ + list_del(&buf->list); + + /* release dmabuf strong ref from tracker */ + dma_buf_put(buf->dmabuf); + + /* put tracker instance back to pool */ + msm_memory_free(inst, MSM_MEM_POOL_DMABUF, buf); +} + +void msm_vidc_memory_put_dmabuf_completely(struct msm_vidc_inst *inst, + struct msm_memory_dmabuf *buf) +{ + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + while (buf->refcount) { + buf->refcount--; + if (!buf->refcount) { + /* remove dmabuf entry from tracker */ + list_del(&buf->list); + + /* release dmabuf strong ref from tracker */ + dma_buf_put(buf->dmabuf); + + /* put tracker instance back to pool */ + msm_memory_free(inst, MSM_MEM_POOL_DMABUF, buf); + break; + } + } } int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map) @@ -446,6 +534,7 @@ static struct msm_vidc_type_size_name buftype_size_name_arr[] = { {MSM_MEM_POOL_MAP, sizeof(struct msm_vidc_map), "MSM_MEM_POOL_MAP" }, {MSM_MEM_POOL_ALLOC, sizeof(struct msm_vidc_alloc), "MSM_MEM_POOL_ALLOC" }, {MSM_MEM_POOL_TIMESTAMP, sizeof(struct msm_vidc_timestamp), "MSM_MEM_POOL_TIMESTAMP" }, + {MSM_MEM_POOL_DMABUF, sizeof(struct msm_memory_dmabuf), "MSM_MEM_POOL_DMABUF" }, }; int msm_memory_pools_init(struct msm_vidc_inst *inst)