On 18.12.2023 12:32, Dikshita Agarwal wrote:
> Allocate interrupt resources, enable the interrupt line and IRQ handling.
> Register the IRQ handler to be called when interrupt occurs and
> the function to be called from IRQ handler thread.
> The threads invoke the driver's response handler which handles
> all different responses from firmware.
>
> Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
> ---
[...]
> +
> +irqreturn_t iris_hfi_isr_handler(int irq, void *data)
> +{
> + struct iris_core *core = data;
> +
> + if (!core)
> + return IRQ_NONE;
Should this even be possible?
> +
> + mutex_lock(&core->lock);
> + call_vpu_op(core, clear_interrupt, core);
> + mutex_unlock(&core->lock);
> +
> + __response_handler(core);
> +
> + if (!call_vpu_op(core, watchdog, core, core->intr_status))
> + enable_irq(irq);
> +
> + return IRQ_HANDLED;
> +}
> diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
> index 8a057cc..8a62986 100644
> --- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
> +++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.h
> @@ -14,4 +14,7 @@ int iris_hfi_core_deinit(struct iris_core *core);
> int iris_hfi_session_open(struct iris_inst *inst);
> int iris_hfi_session_close(struct iris_inst *inst);
>
> +irqreturn_t iris_hfi_isr(int irq, void *data);
> +irqreturn_t iris_hfi_isr_handler(int irq, void *data);
> +
> #endif
> diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
> new file mode 100644
> index 0000000..829f3f6
> --- /dev/null
> +++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi_response.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "hfi_defines.h"
> +#include "iris_hfi_packet.h"
> +#include "iris_hfi_response.h"
> +
> +static void print_sfr_message(struct iris_core *core)
I'm not sure how 'print' relates to what this function does
[...]
> +static int handle_system_error(struct iris_core *core,
> + struct hfi_packet *pkt)
> +{
> + print_sfr_message(core);
> +
> + iris_core_deinit(core);
Either take the return value of /\ into account, or make this function
void.
> +
> + return 0;
> +}
[...]
> +
> +struct sfr_buffer {
> + u32 bufsize;
> + u8 rg_data[];
Looks like you skipped static code checks.. Use __counted_by
[...]
> @@ -17,6 +17,8 @@
> #define CPU_CS_VCICMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x24)
> #define CPU_CS_VCICMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x28)
>
> +#define CPU_CS_A2HSOFTINTCLR_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x1C)
You're mixing upper and lowercase hex throughout your defines.
[...]
> +static int clear_interrupt_iris3(struct iris_core *core)
> +{
> + u32 intr_status = 0, mask = 0;
> + int ret;
> +
> + ret = read_register(core, WRAPPER_INTR_STATUS_IRIS3, &intr_status);
> + if (ret)
> + return ret;
> +
> + mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3 |
> + WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 |
> + CTRL_INIT_IDLE_MSG_BMSK_IRIS3);
unnecesary parentheses
> +
> + if (intr_status & mask)
> + core->intr_status |= intr_status;
> +
> + ret = write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS3, 1);
> +
> + return ret;
why not return write_register directly?
Konrad
@@ -8,6 +8,7 @@ iris-objs += iris_probe.o \
iris_state.o \
iris_helpers.o \
iris_hfi.o \
+ iris_hfi_response.o \
iris_hfi_packet.o \
resources.o \
vpu_common.o \
@@ -6,6 +6,8 @@
#ifndef _HFI_DEFINES_H_
#define _HFI_DEFINES_H_
+#include <linux/types.h>
+
#define HFI_VIDEO_ARCH_LX 0x1
#define HFI_CMD_INIT 0x01000001
@@ -50,4 +52,12 @@
#define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169
+#define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001
+
+struct hfi_debug_header {
+ u32 size;
+ u32 debug_level;
+ u32 reserved[2];
+};
+
#endif
@@ -45,6 +45,7 @@
* @use_tz: a flag that suggests presence of trustzone
* @packet: pointer to packet from driver to fw
* @packet_size: size of packet
+ * @response_packet: a pointer to response packet from fw to driver
* @sys_init_id: id of sys init packet
* @header_id: id of packet header
* @packet_id: id of packet
@@ -52,6 +53,7 @@
* @platform_data: a structure for platform data
* @cap: an array for supported core capabilities
* @instances: a list_head of all instances
+ * @intr_status: interrupt status
*/
struct iris_core {
@@ -82,6 +84,7 @@ struct iris_core {
unsigned int use_tz;
u8 *packet;
u32 packet_size;
+ u8 *response_packet;
u32 sys_init_id;
u32 header_id;
u32 packet_id;
@@ -89,6 +92,7 @@ struct iris_core {
struct platform_data *platform_data;
struct plat_core_cap cap[CORE_CAP_MAX + 1];
struct list_head instances;
+ u32 intr_status;
};
int iris_core_init(struct iris_core *core);
@@ -5,10 +5,11 @@
#include "../firmware.h"
#include "../hfi_queue.h"
+#include "hfi_defines.h"
#include "iris_helpers.h"
#include "iris_hfi.h"
#include "iris_hfi_packet.h"
-#include "hfi_defines.h"
+#include "iris_hfi_response.h"
#include "vpu_common.h"
static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
@@ -253,3 +254,29 @@ int iris_hfi_session_close(struct iris_inst *inst)
return ret;
}
+
+irqreturn_t iris_hfi_isr(int irq, void *data)
+{
+ disable_irq_nosync(irq);
+
+ return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t iris_hfi_isr_handler(int irq, void *data)
+{
+ struct iris_core *core = data;
+
+ if (!core)
+ return IRQ_NONE;
+
+ mutex_lock(&core->lock);
+ call_vpu_op(core, clear_interrupt, core);
+ mutex_unlock(&core->lock);
+
+ __response_handler(core);
+
+ if (!call_vpu_op(core, watchdog, core, core->intr_status))
+ enable_irq(irq);
+
+ return IRQ_HANDLED;
+}
@@ -14,4 +14,7 @@ int iris_hfi_core_deinit(struct iris_core *core);
int iris_hfi_session_open(struct iris_inst *inst);
int iris_hfi_session_close(struct iris_inst *inst);
+irqreturn_t iris_hfi_isr(int irq, void *data);
+irqreturn_t iris_hfi_isr_handler(int irq, void *data);
+
#endif
new file mode 100644
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "hfi_defines.h"
+#include "iris_hfi_packet.h"
+#include "iris_hfi_response.h"
+
+static void print_sfr_message(struct iris_core *core)
+{
+ struct sfr_buffer *vsfr = NULL;
+ u32 vsfr_size = 0;
+ void *p = NULL;
+
+ vsfr = (struct sfr_buffer *)core->sfr.kernel_vaddr;
+ if (vsfr) {
+ if (vsfr->bufsize != core->sfr.size)
+ return;
+ vsfr_size = vsfr->bufsize - sizeof(u32);
+ p = memchr(vsfr->rg_data, '\0', vsfr_size);
+ /* SFR isn't guaranteed to be NULL terminated */
+ if (!p)
+ vsfr->rg_data[vsfr_size - 1] = '\0';
+ }
+}
+
+static int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
+ u32 core_resp_pkt_size)
+{
+ u32 response_pkt_size = 0;
+ u8 *response_limit;
+
+ if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size)
+ return -EINVAL;
+
+ response_limit = core_resp_pkt + core_resp_pkt_size;
+
+ if (response_pkt < core_resp_pkt || response_pkt > response_limit)
+ return -EINVAL;
+
+ response_pkt_size = *(u32 *)response_pkt;
+ if (!response_pkt_size)
+ return -EINVAL;
+
+ if (response_pkt_size < sizeof(struct hfi_packet))
+ return -EINVAL;
+
+ if (response_pkt + response_pkt_size > response_limit)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int validate_hdr_packet(struct iris_core *core,
+ struct hfi_header *hdr)
+{
+ struct hfi_packet *packet;
+ int i, ret = 0;
+ u8 *pkt;
+
+ if (hdr->size < sizeof(*hdr) + sizeof(*packet))
+ return -EINVAL;
+
+ pkt = (u8 *)((u8 *)hdr + sizeof(*hdr));
+
+ for (i = 0; i < hdr->num_packets; i++) {
+ packet = (struct hfi_packet *)pkt;
+ ret = validate_packet(pkt, core->response_packet, core->packet_size);
+ if (ret)
+ return ret;
+
+ pkt += packet->size;
+ }
+
+ return ret;
+}
+
+static int handle_system_error(struct iris_core *core,
+ struct hfi_packet *pkt)
+{
+ print_sfr_message(core);
+
+ iris_core_deinit(core);
+
+ return 0;
+}
+
+static int handle_response(struct iris_core *core, void *response)
+{
+ struct hfi_header *hdr;
+ int ret;
+
+ hdr = (struct hfi_header *)response;
+ ret = validate_hdr_packet(core, hdr);
+ if (ret)
+ return handle_system_error(core, NULL);
+
+ return ret;
+}
+
+static int iris_hfi_queue_read(struct iris_core *core, void *pkt,
+ struct iface_q_info *q_info)
+{
+ u32 tx_req;
+
+ if (!core_in_valid_state(core))
+ return -EINVAL;
+
+ if (!q_info || !q_info->q_array.kernel_vaddr || !pkt) {
+ dev_err(core->dev, "cannot read from shared Q's\n");
+ return -ENODATA;
+ }
+
+ if (read_queue(q_info, pkt, &tx_req))
+ return -ENODATA;
+
+ return 0;
+}
+
+int __response_handler(struct iris_core *core)
+{
+ int ret = 0;
+
+ if (call_vpu_op(core, watchdog, core, core->intr_status)) {
+ struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT};
+
+ mutex_lock(&core->lock);
+ iris_change_core_state(core, IRIS_CORE_ERROR);
+ dev_err(core->dev, "%s: CPU WD error received\n", __func__);
+ mutex_unlock(&core->lock);
+
+ return handle_system_error(core, &pkt);
+ }
+
+ memset(core->response_packet, 0, core->packet_size);
+ while (!iris_hfi_queue_read(core, core->response_packet, &core->message_queue)) {
+ ret = handle_response(core, core->response_packet);
+ if (ret)
+ continue;
+ if (core->state != IRIS_CORE_INIT)
+ break;
+ memset(core->response_packet, 0, core->packet_size);
+ }
+
+ iris_flush_debug_queue(core, core->response_packet, core->packet_size);
+
+ return ret;
+}
+
+void iris_flush_debug_queue(struct iris_core *core,
+ u8 *packet, u32 packet_size)
+{
+ struct hfi_debug_header *pkt;
+ bool local_packet = false;
+ u8 *log;
+
+ if (!packet || !packet_size) {
+ packet = kzalloc(IFACEQ_CORE_PKT_SIZE, GFP_KERNEL);
+ if (!packet)
+ return;
+
+ packet_size = IFACEQ_CORE_PKT_SIZE;
+
+ local_packet = true;
+ }
+
+ while (!iris_hfi_queue_read(core, packet, &core->debug_queue)) {
+ pkt = (struct hfi_debug_header *)packet;
+
+ if (pkt->size < sizeof(*pkt))
+ continue;
+
+ if (pkt->size >= packet_size)
+ continue;
+
+ packet[pkt->size] = '\0';
+ log = (u8 *)packet + sizeof(*pkt) + 1;
+ dev_dbg(core->dev, "%s", log);
+ }
+
+ if (local_packet)
+ kfree(packet);
+}
new file mode 100644
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _IRIS_HFI_RESPONSE_H_
+#define _IRIS_HFI_RESPONSE_H_
+
+#include "iris_core.h"
+
+struct sfr_buffer {
+ u32 bufsize;
+ u8 rg_data[];
+};
+
+int __response_handler(struct iris_core *core);
+void iris_flush_debug_queue(struct iris_core *core,
+ u8 *packet, u32 packet_size);
+
+#endif
@@ -10,9 +10,25 @@
#include "../hfi_queue.h"
#include "iris_core.h"
#include "iris_helpers.h"
+#include "iris_hfi.h"
#include "resources.h"
#include "iris_vidc.h"
+static int init_iris_isr(struct iris_core *core)
+{
+ int ret;
+
+ ret = devm_request_threaded_irq(core->dev, core->irq, iris_hfi_isr,
+ iris_hfi_isr_handler, IRQF_TRIGGER_HIGH, "iris", core);
+ if (ret) {
+ dev_err(core->dev, "%s: Failed to allocate iris IRQ\n", __func__);
+ return ret;
+ }
+ disable_irq_nosync(core->irq);
+
+ return ret;
+}
+
static int iris_register_video_device(struct iris_core *core)
{
struct video_device *vdev;
@@ -86,6 +102,10 @@ static int iris_probe(struct platform_device *pdev)
if (!core->packet)
return -ENOMEM;
+ core->response_packet = devm_kzalloc(core->dev, core->packet_size, GFP_KERNEL);
+ if (!core->response_packet)
+ return -ENOMEM;
+
INIT_LIST_HEAD(&core->instances);
core->reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -96,6 +116,13 @@ static int iris_probe(struct platform_device *pdev)
if (core->irq < 0)
return core->irq;
+ ret = init_iris_isr(core);
+ if (ret) {
+ dev_err_probe(core->dev, ret,
+ "%s: Failed to init isr with %d\n", __func__, ret);
+ return ret;
+ }
+
ret = init_platform(core);
if (ret) {
dev_err_probe(core->dev, ret,
@@ -22,6 +22,8 @@ struct compat_handle {
struct vpu_ops {
int (*boot_firmware)(struct iris_core *core);
int (*raise_interrupt)(struct iris_core *core);
+ int (*clear_interrupt)(struct iris_core *core);
+ int (*watchdog)(struct iris_core *core, u32 intr_status);
};
int init_vpu(struct iris_core *core);
@@ -17,6 +17,8 @@
#define CPU_CS_VCICMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x24)
#define CPU_CS_VCICMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x28)
+#define CPU_CS_A2HSOFTINTCLR_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x1C)
+
/* HFI_CTRL_INIT */
#define CPU_CS_SCIACMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x48)
@@ -57,10 +59,19 @@
#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3 0xfe
#define CTRL_ERROR_STATUS__M_IRIS3 \
CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3
+#define CTRL_INIT_IDLE_MSG_BMSK_IRIS3 \
+ CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3
+
+#define WRAPPER_BASE_OFFS_IRIS3 0x000B0000
+#define WRAPPER_INTR_STATUS_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x0C)
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 0x8
+#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3 0x4
#define CPU_IC_SOFTINT_IRIS3 (CPU_IC_BASE_OFFS_IRIS3 + 0x150)
#define CPU_IC_SOFTINT_H2A_SHFT_IRIS3 0x0
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 0x8
+
static int setup_ucregion_memory_map_iris3(struct iris_core *core)
{
int ret;
@@ -153,9 +164,42 @@ static int raise_interrupt_iris3(struct iris_core *core)
return write_register(core, CPU_IC_SOFTINT_IRIS3, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS3);
}
+static int clear_interrupt_iris3(struct iris_core *core)
+{
+ u32 intr_status = 0, mask = 0;
+ int ret;
+
+ ret = read_register(core, WRAPPER_INTR_STATUS_IRIS3, &intr_status);
+ if (ret)
+ return ret;
+
+ mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3 |
+ WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 |
+ CTRL_INIT_IDLE_MSG_BMSK_IRIS3);
+
+ if (intr_status & mask)
+ core->intr_status |= intr_status;
+
+ ret = write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS3, 1);
+
+ return ret;
+}
+
+static int watchdog_iris3(struct iris_core *core, u32 intr_status)
+{
+ if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3) {
+ dev_err(core->dev, "%s: received watchdog interrupt\n", __func__);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
static const struct vpu_ops iris3_ops = {
.boot_firmware = boot_firmware_iris3,
.raise_interrupt = raise_interrupt_iris3,
+ .clear_interrupt = clear_interrupt_iris3,
+ .watchdog = watchdog_iris3,
};
int init_iris3(struct iris_core *core)