diff mbox series

[v2,21/34] media: iris: implement internal buffer management

Message ID 1702899149-21321-22-git-send-email-quic_dikshita@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series Qualcomm video encoder and decoder driver | expand

Commit Message

Dikshita Agarwal Dec. 18, 2023, 11:32 a.m. UTC
Implement functions for creating, queueing, releasing
and destroying buffers for internal usage.
During any bitstream parameter change, these internal buffers
needs to be reallocated and requeued. To optimize the same,
driver checks for reusability of any buffer and skip
re-allocation/re-queue.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
---
 .../media/platform/qcom/vcodec/iris/hfi_defines.h  |   2 +
 .../media/platform/qcom/vcodec/iris/iris_buffer.c  | 312 +++++++++++++++++++++
 .../media/platform/qcom/vcodec/iris/iris_buffer.h  |  12 +
 drivers/media/platform/qcom/vcodec/iris/iris_hfi.h |   4 +
 .../media/platform/qcom/vcodec/iris/iris_vdec.c    |   3 +
 5 files changed, 333 insertions(+)
diff mbox series

Patch

diff --git a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
index c044f78..ce4eaff 100644
--- a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
+++ b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
@@ -53,6 +53,8 @@ 
 
 #define HFI_PROP_DEC_START_FROM_RAP_FRAME	0x03000169
 
+#define HFI_PROP_COMV_BUFFER_COUNT		0x03000193
+
 #define HFI_SYS_ERROR_WD_TIMEOUT		0x05000001
 
 struct hfi_debug_header {
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_buffer.c b/drivers/media/platform/qcom/vcodec/iris/iris_buffer.c
index 6d4e722..2a3989c 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_buffer.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_buffer.c
@@ -6,8 +6,22 @@ 
 #include "../buffers.h"
 #include "iris_buffer.h"
 #include "iris_helpers.h"
+#include "iris_hfi.h"
+#include "hfi_defines.h"
+#include "iris_hfi_packet.h"
 #include "iris_instance.h"
 
+static const u32 dec_ip_int_buf_type[] = {
+	BUF_BIN,
+	BUF_COMV,
+	BUF_NON_COMV,
+	BUF_LINE,
+};
+
+static const u32 dec_op_int_buf_type[] = {
+	BUF_DPB,
+};
+
 static int input_min_count(struct iris_inst *inst)
 {
 	return MIN_BUFFERS;
@@ -225,3 +239,301 @@  int iris_free_buffers(struct iris_inst *inst,
 
 	return 0;
 }
+
+static int iris_get_internal_buf_info(struct iris_inst *inst,
+				      enum iris_buffer_type buffer_type)
+{
+	struct iris_buffers *buffers;
+	struct iris_core *core;
+	u32 buf_count;
+	u32 buf_size;
+
+	core = inst->core;
+
+	buf_size = call_session_op(core, int_buf_size,
+				   inst, buffer_type);
+
+	buf_count = iris_get_buf_min_count(inst, buffer_type);
+
+	buffers = iris_get_buffer_list(inst, buffer_type);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buf_size && buf_size <= buffers->size &&
+	    buf_count && buf_count <= buffers->min_count) {
+		buffers->reuse = true;
+	} else {
+		buffers->reuse = false;
+		buffers->size = buf_size;
+		buffers->min_count = buf_count;
+	}
+
+	return 0;
+}
+
+int iris_get_internal_buffers(struct iris_inst *inst,
+			      u32 plane)
+{
+	int ret = 0;
+	u32 i = 0;
+
+	if (plane == INPUT_MPLANE) {
+		for (i = 0; i < ARRAY_SIZE(dec_ip_int_buf_type); i++) {
+			ret = iris_get_internal_buf_info(inst, dec_ip_int_buf_type[i]);
+			if (ret)
+				return ret;
+		}
+	} else {
+		return iris_get_internal_buf_info(inst, BUF_DPB);
+	}
+
+	return ret;
+}
+
+static int iris_create_internal_buffer(struct iris_inst *inst,
+				       enum iris_buffer_type buffer_type, u32 index)
+{
+	struct iris_buffers *buffers;
+	struct iris_buffer *buffer;
+	struct iris_core *core;
+
+	core = inst->core;
+
+	buffers = iris_get_buffer_list(inst, buffer_type);
+	if (!buffers)
+		return -EINVAL;
+
+	if (!buffers->size)
+		return 0;
+
+	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&buffer->list);
+	buffer->type = buffer_type;
+	buffer->index = index;
+	buffer->buffer_size = buffers->size;
+	buffer->dma_attrs = DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;
+	list_add_tail(&buffer->list, &buffers->list);
+
+	buffer->kvaddr = dma_alloc_attrs(core->dev, buffer->buffer_size,
+					 &buffer->device_addr, GFP_KERNEL, buffer->dma_attrs);
+
+	if (!buffer->kvaddr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int iris_create_internal_buffers(struct iris_inst *inst,
+					enum iris_buffer_type buffer_type)
+{
+	struct iris_buffers *buffers;
+	int ret = 0;
+	int i;
+
+	buffers = iris_get_buffer_list(inst, buffer_type);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buffers->reuse)
+		return 0;
+
+	for (i = 0; i < buffers->min_count; i++) {
+		ret = iris_create_internal_buffer(inst, buffer_type, i);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int iris_create_input_internal_buffers(struct iris_inst *inst)
+{
+	int ret = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dec_ip_int_buf_type); i++) {
+		ret = iris_create_internal_buffers(inst, dec_ip_int_buf_type[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int iris_create_output_internal_buffers(struct iris_inst *inst)
+{
+	return iris_create_internal_buffers(inst, BUF_DPB);
+}
+
+static int set_num_comv(struct iris_inst *inst)
+{
+	u32 num_comv;
+
+	num_comv = inst->cap[NUM_COMV].value;
+
+	return iris_hfi_set_property(inst,
+					HFI_PROP_COMV_BUFFER_COUNT,
+					HFI_HOST_FLAGS_NONE,
+					HFI_PORT_BITSTREAM,
+					HFI_PAYLOAD_U32,
+					&num_comv,
+					sizeof(u32));
+}
+
+static int iris_queue_internal_buffers(struct iris_inst *inst,
+				       enum iris_buffer_type buffer_type)
+{
+	struct iris_buffer *buffer, *dummy;
+	struct iris_buffers *buffers;
+	int ret = 0;
+
+	if (buffer_type == BUF_COMV) {
+		ret = set_num_comv(inst);
+		if (ret)
+			return ret;
+	}
+
+	buffers = iris_get_buffer_list(inst, buffer_type);
+	if (!buffers)
+		return -EINVAL;
+
+	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
+		if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
+			continue;
+		if (buffer->attr & BUF_ATTR_QUEUED)
+			continue;
+		ret = iris_hfi_queue_buffer(inst, buffer);
+		if (ret)
+			return ret;
+		buffer->attr |= BUF_ATTR_QUEUED;
+	}
+
+	return ret;
+}
+
+int iris_queue_input_internal_buffers(struct iris_inst *inst)
+{
+	int ret = 0;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(dec_ip_int_buf_type); i++) {
+		ret = iris_queue_internal_buffers(inst, dec_ip_int_buf_type[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int iris_queue_output_internal_buffers(struct iris_inst *inst)
+{
+	return iris_queue_internal_buffers(inst, BUF_DPB);
+}
+
+int iris_destroy_internal_buffer(struct iris_inst *inst,
+				 struct iris_buffer *buffer)
+{
+	struct iris_buffer *buf, *dummy;
+	struct iris_buffers *buffers;
+	struct iris_core *core;
+
+	core = inst->core;
+
+	buffers = iris_get_buffer_list(inst, buffer->type);
+	if (!buffers)
+		return -EINVAL;
+
+	list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+		if (buf->device_addr == buffer->device_addr) {
+			list_del(&buf->list);
+			dma_free_attrs(core->dev, buf->buffer_size, buf->kvaddr,
+				       buf->device_addr, buf->dma_attrs);
+			buf->kvaddr = NULL;
+			buf->device_addr = 0;
+			kfree(buf);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int iris_destroy_internal_buffers(struct iris_inst *inst,
+				  u32 plane)
+{
+	struct iris_buffer *buf, *dummy;
+	struct iris_buffers *buffers;
+	const u32 *internal_buf_type;
+	int ret = 0;
+	u32 i, len;
+
+	if (plane == INPUT_MPLANE) {
+		internal_buf_type = dec_ip_int_buf_type;
+		len = ARRAY_SIZE(dec_ip_int_buf_type);
+	} else {
+		internal_buf_type = dec_op_int_buf_type;
+		len = ARRAY_SIZE(dec_op_int_buf_type);
+	}
+
+	for (i = 0; i < len; i++) {
+		buffers = iris_get_buffer_list(inst, internal_buf_type[i]);
+		if (!buffers)
+			return -EINVAL;
+
+		if (buffers->reuse)
+			continue;
+
+		list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
+			ret = iris_destroy_internal_buffer(inst, buf);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int iris_release_internal_buffers(struct iris_inst *inst,
+					 enum iris_buffer_type buffer_type)
+{
+	struct iris_buffer *buffer, *dummy;
+	struct iris_buffers *buffers;
+	int ret = 0;
+
+	buffers = iris_get_buffer_list(inst, buffer_type);
+	if (!buffers)
+		return -EINVAL;
+
+	if (buffers->reuse)
+		return 0;
+
+	list_for_each_entry_safe(buffer, dummy, &buffers->list, list) {
+		if (buffer->attr & BUF_ATTR_PENDING_RELEASE)
+			continue;
+		if (!(buffer->attr & BUF_ATTR_QUEUED))
+			continue;
+		ret = iris_hfi_release_buffer(inst, buffer);
+		if (ret)
+			return ret;
+		buffer->attr |= BUF_ATTR_PENDING_RELEASE;
+	}
+
+	return ret;
+}
+
+int iris_release_input_internal_buffers(struct iris_inst *inst)
+{
+	int ret = 0;
+	u32 i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dec_ip_int_buf_type); i++) {
+		ret = iris_release_internal_buffers(inst, dec_ip_int_buf_type[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_buffer.h b/drivers/media/platform/qcom/vcodec/iris/iris_buffer.h
index 1cd76a9..ece894e 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_buffer.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_buffer.h
@@ -46,4 +46,16 @@  int iris_allocate_buffers(struct iris_inst *inst,
 int iris_free_buffers(struct iris_inst *inst,
 		      enum iris_buffer_type buf_type);
 
+int iris_get_internal_buffers(struct iris_inst *inst,
+			      u32 plane);
+int iris_create_input_internal_buffers(struct iris_inst *inst);
+int iris_create_output_internal_buffers(struct iris_inst *inst);
+int iris_queue_input_internal_buffers(struct iris_inst *inst);
+int iris_queue_output_internal_buffers(struct iris_inst *inst);
+int iris_destroy_internal_buffer(struct iris_inst *inst,
+				 struct iris_buffer *buffer);
+int iris_destroy_internal_buffers(struct iris_inst *inst,
+				  u32 plane);
+int iris_release_input_internal_buffers(struct iris_inst *inst);
+
 #endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
index 4aefdc4..ca2339e 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
@@ -16,6 +16,10 @@  int iris_hfi_session_close(struct iris_inst *inst);
 int iris_hfi_set_property(struct iris_inst *inst,
 			  u32 packet_type, u32 flag, u32 plane, u32 payload_type,
 			  void *payload, u32 payload_size);
+int iris_hfi_queue_buffer(struct iris_inst *inst,
+			  struct iris_buffer *buffer);
+int iris_hfi_release_buffer(struct iris_inst *inst,
+			    struct iris_buffer *buffer);
 
 irqreturn_t iris_hfi_isr(int irq, void *data);
 irqreturn_t iris_hfi_isr_handler(int irq, void *data);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
index b131a50..566048e 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c
@@ -39,6 +39,9 @@  void vdec_inst_init(struct iris_inst *inst)
 	f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
 	f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
 	f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+	inst->buffers.output.min_count = iris_get_buf_min_count(inst, BUF_OUTPUT);
+	inst->buffers.output.actual_count = inst->buffers.output.min_count;
+	inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
 	inst->fw_min_count = 0;
 }