[v2,11/34] media: iris: introduce packetization layer for creating HFI packets

Message ID 1702899149-21321-12-git-send-email-quic_dikshita@quicinc.com
State New
Headers
Series Qualcomm video encoder and decoder driver |

Commit Message

Dikshita Agarwal Dec. 18, 2023, 11:32 a.m. UTC
  Host firmware interface (HFI) is well defined set of interfaces
for communication between host driver and firmware.
The command and responses are exchanged in form of packets.
One or multiple packets are grouped under packet header.
Each packet has packet type which describes the specific HFI
and payload which holds the corresponding value for that HFI.

Sys_init is the first packets sent to firmware, which initializes
the firmware. Sys_image_version packet is to get the firmware
version string.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
---
 drivers/media/platform/qcom/vcodec/iris/Makefile   |   1 +
 .../media/platform/qcom/vcodec/iris/hfi_defines.h  |  15 +++
 .../media/platform/qcom/vcodec/iris/iris_core.h    |  10 ++
 drivers/media/platform/qcom/vcodec/iris/iris_hfi.c |  69 +++++++++++
 .../platform/qcom/vcodec/iris/iris_hfi_packet.c    | 129 +++++++++++++++++++++
 .../platform/qcom/vcodec/iris/iris_hfi_packet.h    |  71 ++++++++++++
 .../media/platform/qcom/vcodec/iris/iris_probe.c   |   5 +
 7 files changed, 300 insertions(+)
 create mode 100644 drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
 create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
 create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
  

Comments

Konrad Dybcio Dec. 18, 2023, 9:50 p.m. UTC | #1
On 12/18/23 12:32, Dikshita Agarwal wrote:
> Host firmware interface (HFI) is well defined set of interfaces
> for communication between host driver and firmware.
> The command and responses are exchanged in form of packets.
> One or multiple packets are grouped under packet header.
> Each packet has packet type which describes the specific HFI
> and payload which holds the corresponding value for that HFI.
> 
> Sys_init is the first packets sent to firmware, which initializes
> the firmware. Sys_image_version packet is to get the firmware
> version string.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> ---
[...]

>   struct iris_core {
> @@ -65,6 +70,11 @@ struct iris_core {
>   	struct mem_desc				sfr;
>   	struct mutex				lock; /* lock for core structure */
>   	unsigned int				use_tz;
> +	u8					*packet;
> +	u32					packet_size;
I'm not sure it's necessary to always keep a reference to the last
packet in the core struct, especially since it needs to be allocated
first anyway

> +	u32					sys_init_id;
This looks like a hyper-defensive measure against some firmware
overtaking attacks.. Or a way to spot random/unwanted resets of
the firmware core..

Is it actually necessary, or does this just serve as a debug
feature?

> +	u32					header_id;
Similar to above..

> +	u32					packet_id;
And here.

I performed some quick CTRL-F-agge around the series and this is
never reset.. Can the firmware cope with this? What if I watch a
veeeery long youtube video that ends up creating more than
(1<<32)-1 HFI packets while playing?

> +
> +enum hfi_packet_host_flags {
> +	HFI_HOST_FLAGS_NONE			= 0x00000000,
> +	HFI_HOST_FLAGS_INTR_REQUIRED		= 0x00000001,
> +	HFI_HOST_FLAGS_RESPONSE_REQUIRED	= 0x00000002,
> +	HFI_HOST_FLAGS_NON_DISCARDABLE		= 0x00000004,
> +	HFI_HOST_FLAGS_GET_PROPERTY		= 0x00000008,
BIT(n)?

> +};
> +
> +enum hfi_packet_firmware_flags {
> +	HFI_FW_FLAGS_NONE		= 0x00000000,
> +	HFI_FW_FLAGS_SUCCESS		= 0x00000001,
> +	HFI_FW_FLAGS_INFORMATION	= 0x00000002,
> +	HFI_FW_FLAGS_SESSION_ERROR	= 0x00000004,
> +	HFI_FW_FLAGS_SYSTEM_ERROR	= 0x00000008,
BIT(n)?

Konrad
  

Patch

diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/media/platform/qcom/vcodec/iris/Makefile
index 74bd344..a2d5d74 100644
--- a/drivers/media/platform/qcom/vcodec/iris/Makefile
+++ b/drivers/media/platform/qcom/vcodec/iris/Makefile
@@ -6,6 +6,7 @@  iris-objs += iris_probe.o \
              iris_state.o \
              iris_helpers.o \
              iris_hfi.o \
+             iris_hfi_packet.o \
              resources.o
 
 obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o
diff --git a/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
new file mode 100644
index 0000000..4c48c90
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/hfi_defines.h
@@ -0,0 +1,15 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _HFI_DEFINES_H_
+#define _HFI_DEFINES_H_
+
+#define HFI_VIDEO_ARCH_LX		0x1
+
+#define HFI_CMD_INIT			0x01000001
+
+#define HFI_PROP_IMAGE_VERSION		0x03000001
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index 2740ff1..de0cfef 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -39,6 +39,11 @@ 
  * @sfr: SFR register memory
  * @lock: a lock for this strucure
  * @use_tz: a flag that suggests presence of trustzone
+ * @packet: pointer to packet from driver to fw
+ * @packet_size: size of packet
+ * @sys_init_id: id of sys init packet
+ * @header_id: id of packet header
+ * @packet_id: id of packet
  */
 
 struct iris_core {
@@ -65,6 +70,11 @@  struct iris_core {
 	struct mem_desc				sfr;
 	struct mutex				lock; /* lock for core structure */
 	unsigned int				use_tz;
+	u8					*packet;
+	u32					packet_size;
+	u32					sys_init_id;
+	u32					header_id;
+	u32					packet_id;
 };
 
 int iris_core_init(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
index 4f51a8c..fe16448 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
@@ -4,8 +4,67 @@ 
  */
 
 #include "../firmware.h"
+#include "../hfi_queue.h"
 #include "iris_helpers.h"
 #include "iris_hfi.h"
+#include "iris_hfi_packet.h"
+
+static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
+{
+	struct iface_q_info *q_info;
+	struct hfi_header *header;
+	u32 packet_size, rx_req;
+	int ret;
+
+	ret = check_core_lock(core);
+	if (ret)
+		return ret;
+
+	if (!core_in_valid_state(core))
+		return -EINVAL;
+
+	q_info = &core->command_queue;
+	if (!q_info || !q_info->q_array.kernel_vaddr || !pkt) {
+		dev_err(core->dev, "cannot write to shared CMD Q's\n");
+		return -ENODATA;
+	}
+
+	header = pkt;
+	packet_size = header->size;
+
+	if (!write_queue(q_info, pkt, packet_size, &rx_req)) {
+		dev_err(core->dev, "queue full\n");
+		return -ENODATA;
+	}
+
+	return ret;
+}
+
+static int sys_init(struct iris_core *core)
+{
+	int ret;
+
+	ret = hfi_packet_sys_init(core, core->packet, core->packet_size);
+	if (ret)
+		return ret;
+
+	ret = iris_hfi_queue_cmd_write(core, core->packet);
+
+	return ret;
+}
+
+static int sys_image_version(struct iris_core *core)
+{
+	int ret;
+
+	ret = hfi_packet_image_version(core, core->packet, core->packet_size);
+	if (ret)
+		return ret;
+
+	ret = iris_hfi_queue_cmd_write(core, core->packet);
+
+	return ret;
+}
 
 #define CP_START           0
 #define CP_SIZE            0x25800000
@@ -46,6 +105,16 @@  int iris_hfi_core_init(struct iris_core *core)
 
 	ret = protect_secure_region(CP_START, CP_SIZE, CP_NONPIXEL_START,
 				    CP_NONPIXEL_SIZE, IRIS_PAS_ID);
+	if (ret)
+		goto error;
+
+	ret = sys_init(core);
+	if (ret)
+		goto error;
+
+	ret = sys_image_version(core);
+	if (ret)
+		goto error;
 
 	return ret;
 
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
new file mode 100644
index 0000000..73bba07
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.c
@@ -0,0 +1,129 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "iris_core.h"
+#include "iris_hfi_packet.h"
+#include "hfi_defines.h"
+
+static int hfi_create_header(u8 *packet, u32 packet_size, u32 session_id,
+			     u32 header_id)
+{
+	struct hfi_header *hdr = (struct hfi_header *)packet;
+
+	if (!packet || packet_size < sizeof(*hdr))
+		return -EINVAL;
+
+	memset(hdr, 0, sizeof(*hdr));
+
+	hdr->size = sizeof(*hdr);
+	hdr->session_id = session_id;
+	hdr->header_id = header_id;
+	hdr->num_packets = 0;
+
+	return 0;
+}
+
+static int hfi_create_packet(u8 *packet, u32 packet_size, u32 pkt_type,
+			     u32 pkt_flags, u32 payload_type, u32 port,
+			     u32 packet_id, void *payload, u32 payload_size)
+{
+	struct hfi_header *hdr;
+	struct hfi_packet *pkt;
+	u32 pkt_size;
+
+	if (!packet)
+		return -EINVAL;
+
+	hdr = (struct hfi_header *)packet;
+	if (hdr->size < sizeof(*hdr))
+		return -EINVAL;
+
+	pkt = (struct hfi_packet *)(packet + hdr->size);
+	pkt_size = sizeof(*pkt) + payload_size;
+	if (packet_size < hdr->size  + pkt_size)
+		return -EINVAL;
+
+	memset(pkt, 0, pkt_size);
+	pkt->size = pkt_size;
+	pkt->type = pkt_type;
+	pkt->flags = pkt_flags;
+	pkt->payload_info = payload_type;
+	pkt->port = port;
+	pkt->packet_id = packet_id;
+	if (payload_size)
+		memcpy((u8 *)pkt + sizeof(*pkt),
+		       payload, payload_size);
+
+	hdr->num_packets++;
+	hdr->size += pkt->size;
+
+	return 0;
+}
+
+int hfi_packet_sys_init(struct iris_core *core,
+			u8 *pkt, u32 pkt_size)
+{
+	u32 payload = 0;
+	int ret;
+
+	ret = hfi_create_header(pkt, pkt_size,
+				0,
+				core->header_id++);
+	if (ret)
+		goto error;
+
+	payload = HFI_VIDEO_ARCH_LX;
+	core->sys_init_id = core->packet_id++;
+	ret = hfi_create_packet(pkt, pkt_size,
+				HFI_CMD_INIT,
+				(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+				HFI_HOST_FLAGS_INTR_REQUIRED |
+				HFI_HOST_FLAGS_NON_DISCARDABLE),
+				HFI_PAYLOAD_U32,
+				HFI_PORT_NONE,
+				core->sys_init_id,
+				&payload,
+				sizeof(u32));
+	if (ret)
+		goto error;
+
+	return ret;
+
+error:
+	dev_err(core->dev, "%s: create sys init packet failed\n", __func__);
+
+	return ret;
+}
+
+int hfi_packet_image_version(struct iris_core *core,
+			     u8 *pkt, u32 pkt_size)
+{
+	int ret;
+
+	ret = hfi_create_header(pkt, pkt_size,
+				0,
+				core->header_id++);
+	if (ret)
+		goto error;
+
+	ret = hfi_create_packet(pkt, pkt_size,
+				HFI_PROP_IMAGE_VERSION,
+				(HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+				HFI_HOST_FLAGS_INTR_REQUIRED |
+				HFI_HOST_FLAGS_GET_PROPERTY),
+				HFI_PAYLOAD_NONE,
+				HFI_PORT_NONE,
+				core->packet_id++,
+				NULL, 0);
+	if (ret)
+		goto error;
+
+	return ret;
+
+error:
+	dev_err(core->dev, "%s: create image version packet failed\n", __func__);
+
+	return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
new file mode 100644
index 0000000..e36612c
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_packet.h
@@ -0,0 +1,71 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _IRIS_HFI_PACKET_H_
+#define _IRIS_HFI_PACKET_H_
+
+struct hfi_header {
+	u32 size;
+	u32 session_id;
+	u32 header_id;
+	u32 reserved[4];
+	u32 num_packets;
+};
+
+struct hfi_packet {
+	u32 size;
+	u32 type;
+	u32 flags;
+	u32 payload_info;
+	u32 port;
+	u32 packet_id;
+	u32 reserved[2];
+};
+
+enum hfi_packet_host_flags {
+	HFI_HOST_FLAGS_NONE			= 0x00000000,
+	HFI_HOST_FLAGS_INTR_REQUIRED		= 0x00000001,
+	HFI_HOST_FLAGS_RESPONSE_REQUIRED	= 0x00000002,
+	HFI_HOST_FLAGS_NON_DISCARDABLE		= 0x00000004,
+	HFI_HOST_FLAGS_GET_PROPERTY		= 0x00000008,
+};
+
+enum hfi_packet_firmware_flags {
+	HFI_FW_FLAGS_NONE		= 0x00000000,
+	HFI_FW_FLAGS_SUCCESS		= 0x00000001,
+	HFI_FW_FLAGS_INFORMATION	= 0x00000002,
+	HFI_FW_FLAGS_SESSION_ERROR	= 0x00000004,
+	HFI_FW_FLAGS_SYSTEM_ERROR	= 0x00000008,
+};
+
+enum hfi_packet_payload_info {
+	HFI_PAYLOAD_NONE	= 0x00000000,
+	HFI_PAYLOAD_U32		= 0x00000001,
+	HFI_PAYLOAD_S32		= 0x00000002,
+	HFI_PAYLOAD_U64		= 0x00000003,
+	HFI_PAYLOAD_S64		= 0x00000004,
+	HFI_PAYLOAD_STRUCTURE	= 0x00000005,
+	HFI_PAYLOAD_BLOB	= 0x00000006,
+	HFI_PAYLOAD_STRING	= 0x00000007,
+	HFI_PAYLOAD_Q16		= 0x00000008,
+	HFI_PAYLOAD_U32_ENUM	= 0x00000009,
+	HFI_PAYLOAD_32_PACKED	= 0x0000000a,
+	HFI_PAYLOAD_U32_ARRAY	= 0x0000000b,
+	HFI_PAYLOAD_S32_ARRAY	= 0x0000000c,
+	HFI_PAYLOAD_64_PACKED	= 0x0000000d,
+};
+
+enum hfi_packet_port_type {
+	HFI_PORT_NONE		= 0x00000000,
+	HFI_PORT_BITSTREAM	= 0x00000001,
+	HFI_PORT_RAW		= 0x00000002,
+};
+
+int hfi_packet_sys_init(struct iris_core *core,
+			u8 *pkt, u32 pkt_size);
+int hfi_packet_image_version(struct iris_core *core,
+			     u8 *pkt, u32 pkt_size);
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
index f39b4aa..570c64e 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
@@ -79,6 +79,11 @@  static int iris_probe(struct platform_device *pdev)
 	core->state = IRIS_CORE_DEINIT;
 	mutex_init(&core->lock);
 
+	core->packet_size = IFACEQ_CORE_PKT_SIZE;
+	core->packet = devm_kzalloc(core->dev, core->packet_size, GFP_KERNEL);
+	if (!core->packet)
+		return -ENOMEM;
+
 	core->reg_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(core->reg_base))
 		return PTR_ERR(core->reg_base);