diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index a4db8b968f..d9f1aa96a2 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -310,6 +310,8 @@ int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst, void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst); int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, enum msm_vidc_buffer_type type); +int msm_vidc_flush_delayed_unmap_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type); struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *vbuf); struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core, diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index dc850bfb93..e8577be7a6 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -56,6 +56,7 @@ struct msm_vidc_mappings_info { struct msm_vidc_buffers_info { struct msm_vidc_buffers input; struct msm_vidc_buffers output; + struct msm_vidc_buffers read_only; struct msm_vidc_buffers input_meta; struct msm_vidc_buffers output_meta; struct msm_vidc_buffers bin; diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 9abc4eccec..487e8a3e50 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -141,6 +141,7 @@ enum msm_vidc_buffer_type { MSM_VIDC_BUF_OUTPUT = 2, MSM_VIDC_BUF_INPUT_META = 3, MSM_VIDC_BUF_OUTPUT_META = 4, + MSM_VIDC_BUF_READ_ONLY = 5, MSM_VIDC_BUF_QUEUE = 10, MSM_VIDC_BUF_BIN = 20, MSM_VIDC_BUF_ARP = 21, @@ -757,6 +758,7 @@ struct msm_vidc_map { u64 device_addr; struct sg_table *table; struct dma_buf_attachment *attach; + u32 skip_delayed_unmap:1; }; struct msm_vidc_mappings { diff --git a/driver/vidc/inc/msm_vidc_memory.h b/driver/vidc/inc/msm_vidc_memory.h index cb183ad3f9..7522792de6 100644 --- a/driver/vidc/inc/msm_vidc_memory.h +++ b/driver/vidc/inc/msm_vidc_memory.h @@ -17,6 +17,8 @@ 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); +int msm_vidc_memory_unmap_completely(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); diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index 93d52f7489..82d245ca83 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -749,6 +749,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) INIT_LIST_HEAD(&inst->buffers.input_meta.list); INIT_LIST_HEAD(&inst->buffers.output.list); INIT_LIST_HEAD(&inst->buffers.output_meta.list); + INIT_LIST_HEAD(&inst->buffers.read_only.list); INIT_LIST_HEAD(&inst->buffers.bin.list); INIT_LIST_HEAD(&inst->buffers.arp.list); INIT_LIST_HEAD(&inst->buffers.comv.list); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 9cc7817039..302bd5a222 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -881,6 +881,8 @@ struct msm_vidc_buffers *msm_vidc_get_buffers( return &inst->buffers.output; case MSM_VIDC_BUF_OUTPUT_META: return &inst->buffers.output_meta; + case MSM_VIDC_BUF_READ_ONLY: + return &inst->buffers.read_only; case MSM_VIDC_BUF_BIN: return &inst->buffers.bin; case MSM_VIDC_BUF_ARP: @@ -1747,6 +1749,65 @@ static int vb2_buffer_to_driver(struct vb2_buffer *vb2, return rc; } +int msm_vidc_process_readonly_buffers(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct msm_vidc_buffer *ro_buf, *dummy; + struct msm_vidc_buffers *ro_buffers; + + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!is_decode_session(inst) || !is_output_buffer(buf->type)) + return 0; + + ro_buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_READ_ONLY, __func__); + if (!ro_buffers) + return -EINVAL; + + /* + * check if buffer present in ro_buffers list + * if present: add ro flag to buf and remove from ro_buffers list + * if not present: do nothing + */ + list_for_each_entry_safe(ro_buf, dummy, &ro_buffers->list, list) { + if (ro_buf->device_addr == buf->device_addr) { + buf->attr |= MSM_VIDC_ATTR_READ_ONLY; + print_vidc_buffer(VIDC_LOW, "low", "ro buf removed", inst, ro_buf); + list_del(&ro_buf->list); + kfree(ro_buf); + break; + } + } + return rc; +} + +int msm_vidc_unmap_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type) +{ + int rc = 0; + struct msm_vidc_mappings *mappings; + struct msm_vidc_map *map, *dummy; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mappings = msm_vidc_get_mappings(inst, type, __func__); + if (!mappings) + return -EINVAL; + + list_for_each_entry_safe(map, dummy, &mappings->list, list) { + msm_vidc_memory_unmap_completely(inst->core, map); + } + + return rc; +} + int msm_vidc_unmap_driver_buf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) { @@ -1786,8 +1847,76 @@ int msm_vidc_unmap_driver_buf(struct msm_vidc_inst *inst, if (!map->refcount) { list_del(&map->list); kfree(map); + map = NULL; + } else { + /* we should not be here except decoder output buffer */ + if (!is_decode_session(inst) || !is_output_buffer(buf->type)) { + print_vidc_buffer(VIDC_ERR, "err ", "non zero refcount found", inst, buf); + return -EINVAL; + } } + return rc; +} + +int msm_vidc_map_driver_buf(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct msm_vidc_mappings *mappings; + struct msm_vidc_map *map; + bool found = false; + + if (!inst || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mappings = msm_vidc_get_mappings(inst, buf->type, __func__); + if (!mappings) + return -EINVAL; + + /* + * new buffer: map twice for lazy unmap feature sake + * existing buffer: map once + */ + list_for_each_entry(map, &mappings->list, list) { + if (map->dmabuf == buf->dmabuf) { + found = true; + break; + } + } + if (!found) { + /* new buffer case */ + map = kzalloc(sizeof(struct msm_vidc_map), GFP_KERNEL); + if (!map) { + i_vpr_e(inst, "%s: alloc failed\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&map->list); + map->type = buf->type; + map->dmabuf = msm_vidc_memory_get_dmabuf(buf->fd); + if (!map->dmabuf) + return -EINVAL; + map->region = msm_vidc_get_buffer_region(inst, buf->type, __func__); + /* lazy unmap feature not needed for decoder output buffers */ + if (is_decode_session(inst) && is_output_buffer(buf->type)) { + map->skip_delayed_unmap = 1; + rc = msm_vidc_memory_map(inst->core, map); + if (rc) { + msm_vidc_memory_put_dmabuf(map->dmabuf); + kfree(map); + return rc; + } + } + list_add_tail(&map->list, &mappings->list); + } + rc = msm_vidc_memory_map(inst->core, map); + if (rc) + return rc; + + buf->device_addr = map->device_addr; + return 0; } @@ -1801,9 +1930,7 @@ int msm_vidc_put_driver_buf(struct msm_vidc_inst *inst, return -EINVAL; } - rc = msm_vidc_unmap_driver_buf(inst, buf); - if (rc) - return rc; + msm_vidc_unmap_driver_buf(inst, buf); msm_vidc_memory_put_dmabuf(buf->dmabuf); @@ -1811,61 +1938,7 @@ int msm_vidc_put_driver_buf(struct msm_vidc_inst *inst, list_del(&buf->list); kfree(buf); - return 0; -} - -int msm_vidc_map_driver_buf(struct msm_vidc_inst *inst, - struct msm_vidc_buffer *buf) -{ - int rc = 0; - struct msm_vidc_mappings *mappings; - struct msm_vidc_map *map = NULL; - bool found = false; - - if (!inst || !buf) { - d_vpr_e("%s: invalid params\n", __func__); - return -EINVAL; - } - - mappings = msm_vidc_get_mappings(inst, buf->type, __func__); - if (!mappings) - return -EINVAL; - - /* check if it is an existing one */ - list_for_each_entry(map, &mappings->list, list) { - if (map->dmabuf == buf->dmabuf) { - found = true; - break; - } - } - if (found) { - /* skip mapping for RO buffer */ - if (!(buf->attr & MSM_VIDC_ATTR_READ_ONLY)) { - rc = msm_vidc_memory_map(inst->core, map); - if (rc) - return -ENOMEM; - buf->device_addr = map->device_addr; - } - return 0; - } - map = kzalloc(sizeof(struct msm_vidc_map), GFP_KERNEL); - if (!map) { - i_vpr_e(inst, "%s: alloc failed\n", __func__); - return -ENOMEM; - } - INIT_LIST_HEAD(&map->list); - map->type = buf->type; - map->dmabuf = buf->dmabuf; - map->region = msm_vidc_get_buffer_region(inst, buf->type, __func__); - rc = msm_vidc_memory_map(inst->core, map); - if (rc) { - kfree(map); - return -ENOMEM; - } - buf->device_addr = map->device_addr; - list_add_tail(&map->list, &mappings->list); - - return 0; + return rc; } struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, @@ -1874,9 +1947,7 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, int rc = 0; struct msm_vidc_buffer *buf = NULL; struct msm_vidc_buffers *buffers; - struct dma_buf *dmabuf; enum msm_vidc_buffer_type buf_type; - bool found = false; if (!inst || !vb2) { d_vpr_e("%s: invalid params\n", __func__); @@ -1891,58 +1962,25 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, if (!buffers) return NULL; - dmabuf = msm_vidc_memory_get_dmabuf(vb2->planes[0].m.fd); - if (!dmabuf) + buf = kzalloc(sizeof(struct msm_vidc_buffer), GFP_KERNEL); + if (!buf) { + i_vpr_e(inst, "%s: alloc failed\n", __func__); return NULL; - - /* check if it is an existing buffer */ - list_for_each_entry(buf, &buffers->list, list) { - if (buf->dmabuf == dmabuf && - buf->data_offset == vb2->planes[0].data_offset) { - found = true; - break; - } } - if (found) { - /* only YUV buffers are allowed to repeat */ - if ((is_decode_session(inst) && vb2->type != OUTPUT_MPLANE) || - (is_encode_session(inst) && vb2->type != INPUT_MPLANE)) { - print_vidc_buffer(VIDC_ERR, "err ", - "existing buffer", inst, buf); - goto error; - } - /* for decoder, YUV with RO flag are allowed to repeat */ - if (is_decode_session(inst) && - !(buf->attr & MSM_VIDC_ATTR_READ_ONLY)) { - print_vidc_buffer(VIDC_ERR, "err ", - "existing buffer without RO flag", inst, buf); - goto error; - } - /* for encoder, treat the repeated buffer as new buffer */ - if (is_encode_session(inst) && vb2->type == INPUT_MPLANE) - found = false; - } - if (!found) { - buf = kzalloc(sizeof(struct msm_vidc_buffer), GFP_KERNEL); - if (!buf) { - i_vpr_e(inst, "%s: alloc failed\n", __func__); - goto error; - } - buf->dmabuf = dmabuf; - INIT_LIST_HEAD(&buf->list); - list_add_tail(&buf->list, &buffers->list); - } else { - /* reset all attributes except read only */ - buf->attr &= MSM_VIDC_ATTR_READ_ONLY; - } - - /* treat every buffer as deferred buffer initially */ - buf->attr |= MSM_VIDC_ATTR_DEFERRED; + INIT_LIST_HEAD(&buf->list); + list_add_tail(&buf->list, &buffers->list); rc = vb2_buffer_to_driver(vb2, buf); if (rc) goto error; + buf->dmabuf = msm_vidc_memory_get_dmabuf(buf->fd); + if (!buf->dmabuf) + goto error; + + /* treat every buffer as deferred buffer initially */ + buf->attr |= MSM_VIDC_ATTR_DEFERRED; + rc = msm_vidc_map_driver_buf(inst, buf); if (rc) goto error; @@ -1950,9 +1988,9 @@ struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, return buf; error: - msm_vidc_memory_put_dmabuf(dmabuf); - if (!found) - kfree(buf); + msm_vidc_memory_put_dmabuf(buf->dmabuf); + list_del(&buf->list); + kfree(buf); return NULL; } @@ -2159,6 +2197,12 @@ static int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buf msm_vidc_update_cap_value(inst, CODEC_CONFIG, 0, __func__); } + if (is_decode_session(inst) && is_output_buffer(buf->type)) { + rc = msm_vidc_process_readonly_buffers(inst, buf); + if (rc) + return rc; + } + print_vidc_buffer(VIDC_HIGH, "high", "qbuf", inst, buf); meta = get_meta_buffer(inst, buf); if (meta) @@ -3039,6 +3083,7 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, /* flush deferred buffers */ msm_vidc_flush_buffers(inst, buffer_type); + msm_vidc_flush_delayed_unmap_buffers(inst, buffer_type); return 0; error: @@ -3694,7 +3739,7 @@ int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, buffer_type[1] = MSM_VIDC_BUF_OUTPUT; } else { i_vpr_h(inst, "%s: invalid buffer type %d\n", - __func__, type); + __func__, type); return -EINVAL; } @@ -3706,8 +3751,9 @@ int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, list_for_each_entry_safe(buf, dummy, &buffers->list, list) { if (buf->attr & MSM_VIDC_ATTR_QUEUED || buf->attr & MSM_VIDC_ATTR_DEFERRED) { - print_vidc_buffer(VIDC_ERR, "err ", "flushing buffer", inst, buf); - msm_vidc_vb2_buffer_done(inst, buf); + print_vidc_buffer(VIDC_HIGH, "high", "flushing buffer", inst, buf); + if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) + msm_vidc_vb2_buffer_done(inst, buf); msm_vidc_put_driver_buf(inst, buf); } } @@ -3716,15 +3762,75 @@ int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, return rc; } +int msm_vidc_flush_delayed_unmap_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type) +{ + int rc = 0; + struct msm_vidc_mappings *maps; + struct msm_vidc_map *map, *dummy; + struct msm_vidc_buffer *ro_buf, *ro_dummy; + enum msm_vidc_buffer_type buffer_type[2]; + int i; + bool found = false; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (type == MSM_VIDC_BUF_INPUT) { + buffer_type[0] = MSM_VIDC_BUF_INPUT_META; + buffer_type[1] = MSM_VIDC_BUF_INPUT; + } else if (type == MSM_VIDC_BUF_OUTPUT) { + buffer_type[0] = MSM_VIDC_BUF_OUTPUT_META; + buffer_type[1] = MSM_VIDC_BUF_OUTPUT; + } else { + i_vpr_h(inst, "%s: invalid buffer type %d\n", + __func__, type); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(buffer_type); i++) { + maps = msm_vidc_get_mappings(inst, buffer_type[i], __func__); + if (!maps) + return -EINVAL; + + list_for_each_entry_safe(map, dummy, &maps->list, list) { + /* + * decoder output bufs will have skip_delayed_unmap = true + * unmap all decoder output buffers except those present in + * read_only buffers list + */ + if (!map->skip_delayed_unmap) + continue; + found = false; + list_for_each_entry_safe(ro_buf, ro_dummy, + &inst->buffers.read_only.list, list) { + if (map->dmabuf == ro_buf->dmabuf) { + found = true; + break; + } + } + /* completely unmap */ + if (!found) + msm_vidc_memory_unmap_completely(inst->core, map); + } + } + + return rc; +} + void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) { struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buf, *dummy; - static const enum msm_vidc_buffer_type buf_types[] = { + static const enum msm_vidc_buffer_type ext_buf_types[] = { MSM_VIDC_BUF_INPUT, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_BUF_INPUT_META, MSM_VIDC_BUF_OUTPUT_META, + }; + static const enum msm_vidc_buffer_type internal_buf_types[] = { MSM_VIDC_BUF_BIN, MSM_VIDC_BUF_ARP, MSM_VIDC_BUF_COMV, @@ -3741,19 +3847,35 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) return; } - for (i = 0; i < ARRAY_SIZE(buf_types); i++) { - buffers = msm_vidc_get_buffers(inst, buf_types[i], __func__); + for (i = 0; i < ARRAY_SIZE(internal_buf_types); i++) { + buffers = msm_vidc_get_buffers(inst, internal_buf_types[i], __func__); if (!buffers) continue; list_for_each_entry_safe(buf, dummy, &buffers->list, list) { i_vpr_h(inst, - "destroying buffer: type %d idx %d fd %d addr %#x size %d\n", + "destroying internal buffer: type %d idx %d fd %d addr %#x size %d\n", buf->type, buf->index, buf->fd, buf->device_addr, buf->buffer_size); - if (is_internal_buffer(buf->type)) - msm_vidc_destroy_internal_buffer(inst, buf); - else - msm_vidc_put_driver_buf(inst, buf); + msm_vidc_destroy_internal_buffer(inst, buf); } + msm_vidc_unmap_buffers(inst, internal_buf_types[i]); + } + + for (i = 0; i < ARRAY_SIZE(ext_buf_types); i++) { + buffers = msm_vidc_get_buffers(inst, ext_buf_types[i], __func__); + if (!buffers) + continue; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + print_vidc_buffer(VIDC_ERR, "err", "destroying ", inst, buf); + msm_vidc_put_driver_buf(inst, buf); + } + msm_vidc_unmap_buffers(inst, ext_buf_types[i]); + } + + list_for_each_entry_safe(buf, dummy, &inst->buffers.read_only.list, list) { + print_vidc_buffer(VIDC_ERR, "err", "destroying ro buffer", inst, buf); + list_del(&buf->list); + kfree(buf); } } diff --git a/driver/vidc/src/msm_vidc_memory.c b/driver/vidc/src/msm_vidc_memory.c index 3316eb46d5..4218196e0c 100644 --- a/driver/vidc/src/msm_vidc_memory.c +++ b/driver/vidc/src/msm_vidc_memory.c @@ -116,11 +116,14 @@ int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map) goto error_attach; } - /* - * Get the scatterlist for the given attachment - * Mapping of sg is taken care by map attachment - */ - attach->dma_map_attrs = DMA_ATTR_DELAYED_UNMAP; + if (!map->skip_delayed_unmap) { + /* + * Get the scatterlist for the given attachment + * Mapping of sg is taken care by map attachment + */ + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + } + /* * We do not need dma_map function to perform cache operations * on the whole buffer size and hence pass skip sync flag. @@ -148,6 +151,11 @@ int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map) map->table = table; map->attach = attach; map->refcount++; + + d_vpr_l( + "%s: type %d device_addr %#x refcount %d region %d\n", + __func__, map->type, map->device_addr, map->refcount, map->region); + return 0; error_sg: @@ -159,7 +167,8 @@ error_cb: return rc; } -int msm_vidc_memory_unmap(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) { int rc = 0; @@ -178,6 +187,10 @@ int msm_vidc_memory_unmap(struct msm_vidc_core *core, struct msm_vidc_map *map) if (map->refcount) goto exit; + d_vpr_l( + "%s: type %d device_addr %#x refcount %d region %d\n", + __func__, map->type, map->device_addr, map->refcount, map->region); + dma_buf_unmap_attachment(map->attach, map->table, DMA_BIDIRECTIONAL); dma_buf_detach(map->dmabuf, map->attach); @@ -190,6 +203,33 @@ exit: return rc; } +int msm_vidc_memory_unmap_completely(struct msm_vidc_core *core, + struct msm_vidc_map *map) +{ + int rc = 0; + + if (!core || !map) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!map->refcount) + return 0; + + while (map->refcount) { + rc = msm_vidc_memory_unmap(core, map); + if (rc) + break; + if (!map->refcount) { + list_del(&map->list); + kfree(map); + map = NULL; + break; + } + } + return rc; +} + int msm_vidc_memory_alloc(struct msm_vidc_core *core, struct msm_vidc_alloc *mem) { int rc = 0; diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index 521a7934ce..a9a3a7d640 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -481,6 +481,61 @@ static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags) return driver_flags; } +static int handle_read_only_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer) +{ + struct msm_vidc_buffer *ro_buf; + struct msm_vidc_buffers *ro_buffers; + bool found = false; + + if (!inst || !buffer) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!is_decode_session(inst) || !is_output_buffer(buffer->type)) + return 0; + + ro_buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_READ_ONLY, __func__); + if (!ro_buffers) + return -EINVAL; + + list_for_each_entry(ro_buf, &ro_buffers->list, list) { + if (ro_buf->device_addr == buffer->device_addr) { + found = true; + break; + } + } + + /* + * RO flag: add to read_only list if buffer is not present + * if present, do nothing + * Without RO flag: remove buffer from read_only list if present + * if not present, do not error out + */ + if (buffer->attr & MSM_VIDC_ATTR_READ_ONLY) { + if (!found) { + ro_buf = kmemdup(buffer, sizeof(struct msm_vidc_buffer), GFP_KERNEL); + if (!ro_buf) { + i_vpr_e(inst, "%s: buffer alloc failed\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&ro_buf->list); + list_add_tail(&ro_buf->list, &ro_buffers->list); + print_vidc_buffer(VIDC_LOW, "low", "ro buf added", inst, ro_buf); + } + } else { + if (found) { + print_vidc_buffer(VIDC_LOW, "low", "ro buf deleted", inst, ro_buf); + list_del(&ro_buf->list); + kfree(ro_buf); + ro_buf = NULL; + } + } + + return 0; +} + static int handle_input_buffer(struct msm_vidc_inst *inst, struct hfi_buffer *buffer) { @@ -502,14 +557,15 @@ static int handle_input_buffer(struct msm_vidc_inst *inst, found = false; list_for_each_entry(buf, &buffers->list, list) { - if (buf->device_addr == buffer->base_address) { + if (buf->index == buffer->index) { found = true; break; } } if (!found) { - i_vpr_e(inst, "%s: buffer not found for idx %d addr %#x\n", - __func__, buffer->index, buffer->base_address); + i_vpr_e(inst, "%s: invalid buffer idx %d addr %#x data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); return -EINVAL; } @@ -556,14 +612,15 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, found = false; list_for_each_entry(buf, &buffers->list, list) { - if (buf->device_addr == buffer->base_address) { + if (buf->index == buffer->index) { found = true; break; } } if (!found) { - i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n", - __func__, buffer->index, buffer->base_address); + i_vpr_e(inst, "%s: invalid idx %d daddr %#x data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); return -EINVAL; } buf->data_offset = buffer->data_offset; @@ -615,11 +672,15 @@ static int handle_output_buffer(struct msm_vidc_inst *inst, } } - if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) - buf->attr |= MSM_VIDC_ATTR_READ_ONLY; - else - buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; - + if (is_decode_session(inst)) { + if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) + buf->attr |= MSM_VIDC_ATTR_READ_ONLY; + else + buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; + rc = handle_read_only_buffer(inst, buf); + if (rc) + return rc; + } buf->flags = 0; buf->flags = get_driver_buffer_flags(inst, buffer->flags); @@ -651,14 +712,15 @@ static int handle_input_metadata_buffer(struct msm_vidc_inst *inst, found = false; list_for_each_entry(buf, &buffers->list, list) { - if (buf->device_addr == buffer->base_address) { + if (buf->index == buffer->index) { found = true; break; } } if (!found) { - i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n", - __func__, buffer->index, buffer->base_address); + i_vpr_e(inst, "%s: invalid idx %d daddr %#x data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); return -EINVAL; } /* attach dequeued flag for, only last frame in the batch */ @@ -701,14 +763,15 @@ static int handle_output_metadata_buffer(struct msm_vidc_inst *inst, found = false; list_for_each_entry(buf, &buffers->list, list) { - if (buf->device_addr == buffer->base_address) { + if (buf->index == buffer->index) { found = true; break; } } if (!found) { - i_vpr_e(inst, "%s: invalid idx %d daddr %#x\n", - __func__, buffer->index, buffer->base_address); + i_vpr_e(inst, "%s: invalid idx %d daddr %#x data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); return -EINVAL; } @@ -756,9 +819,7 @@ static int handle_dequeue_buffers(struct msm_vidc_inst* inst) buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE; msm_vidc_vb2_buffer_done(inst, buf); } - /* do not unmap / delete read only buffer */ - if (!(buf->attr & MSM_VIDC_ATTR_READ_ONLY)) - msm_vidc_put_driver_buf(inst, buf); + msm_vidc_put_driver_buf(inst, buf); } } }