root/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include <linux/bitfield.h>
#include <media/v4l2-mem2mem.h>

#include "iris_hfi_gen1.h"
#include "iris_hfi_gen1_defines.h"
#include "iris_instance.h"
#include "iris_vdec.h"
#include "iris_vpu_buffer.h"

static void iris_hfi_gen1_read_changed_params(struct iris_inst *inst,
                                              struct hfi_msg_event_notify_pkt *pkt)
{
        struct v4l2_pix_format_mplane *pixmp_ip = &inst->fmt_src->fmt.pix_mp;
        struct v4l2_pix_format_mplane *pixmp_op = &inst->fmt_dst->fmt.pix_mp;
        u32 num_properties_changed = pkt->event_data2;
        u8 *data_ptr = (u8 *)&pkt->ext_event_data[0];
        u32 primaries, matrix_coeff, transfer_char;
        struct hfi_dpb_counts *iris_vpu_dpb_count;
        struct hfi_profile_level *profile_level;
        struct hfi_buffer_requirements *bufreq;
        struct hfi_extradata_input_crop *crop;
        struct hfi_colour_space *colour_info;
        struct iris_core *core = inst->core;
        u32 colour_description_present_flag;
        u32 video_signal_type_present_flag;
        struct hfi_event_data event = {0};
        struct hfi_bit_depth *pixel_depth;
        struct hfi_pic_struct *pic_struct;
        struct hfi_framesize *frame_sz;
        struct vb2_queue *dst_q;
        struct v4l2_ctrl *ctrl;
        u32 full_range, ptype;

        do {
                ptype = *((u32 *)data_ptr);
                switch (ptype) {
                case HFI_PROPERTY_PARAM_FRAME_SIZE:
                        data_ptr += sizeof(u32);
                        frame_sz = (struct hfi_framesize *)data_ptr;
                        event.width = frame_sz->width;
                        event.height = frame_sz->height;
                        data_ptr += sizeof(*frame_sz);
                        break;
                case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
                        data_ptr += sizeof(u32);
                        profile_level = (struct hfi_profile_level *)data_ptr;
                        event.profile = profile_level->profile;
                        event.level = profile_level->level;
                        data_ptr += sizeof(*profile_level);
                        break;
                case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
                        data_ptr += sizeof(u32);
                        pixel_depth = (struct hfi_bit_depth *)data_ptr;
                        event.bit_depth = pixel_depth->bit_depth;
                        data_ptr += sizeof(*pixel_depth);
                        break;
                case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
                        data_ptr += sizeof(u32);
                        pic_struct = (struct hfi_pic_struct *)data_ptr;
                        event.pic_struct = pic_struct->progressive_only;
                        data_ptr += sizeof(*pic_struct);
                        break;
                case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
                        data_ptr += sizeof(u32);
                        colour_info = (struct hfi_colour_space *)data_ptr;
                        event.colour_space = colour_info->colour_space;
                        data_ptr += sizeof(*colour_info);
                        break;
                case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
                        data_ptr += sizeof(u32);
                        event.entropy_mode = *(u32 *)data_ptr;
                        data_ptr += sizeof(u32);
                        break;
                case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
                        data_ptr += sizeof(u32);
                        bufreq = (struct hfi_buffer_requirements *)data_ptr;
                        event.buf_count = bufreq->count_min;
                        data_ptr += sizeof(*bufreq);
                        break;
                case HFI_INDEX_EXTRADATA_INPUT_CROP:
                        data_ptr += sizeof(u32);
                        crop = (struct hfi_extradata_input_crop *)data_ptr;
                        event.input_crop.left = crop->left;
                        event.input_crop.top = crop->top;
                        event.input_crop.width = crop->width;
                        event.input_crop.height = crop->height;
                        data_ptr += sizeof(*crop);
                        break;
                case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS:
                        data_ptr += sizeof(u32);
                        iris_vpu_dpb_count = (struct hfi_dpb_counts *)data_ptr;
                        event.buf_count = iris_vpu_dpb_count->fw_min_count;
                        data_ptr += sizeof(*iris_vpu_dpb_count);
                        break;
                default:
                        break;
                }
                num_properties_changed--;
        } while (num_properties_changed > 0);

        pixmp_ip->width = event.width;
        pixmp_ip->height = event.height;

        pixmp_op->width = ALIGN(event.width, 128);
        pixmp_op->height = ALIGN(event.height, 32);
        pixmp_op->plane_fmt[0].bytesperline = ALIGN(event.width, 128);
        pixmp_op->plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT);

        matrix_coeff =  FIELD_GET(GENMASK(7, 0), event.colour_space);
        transfer_char = FIELD_GET(GENMASK(15, 8), event.colour_space);
        primaries = FIELD_GET(GENMASK(23, 16), event.colour_space);
        colour_description_present_flag = FIELD_GET(GENMASK(24, 24), event.colour_space);
        full_range = FIELD_GET(GENMASK(25, 25), event.colour_space);
        video_signal_type_present_flag = FIELD_GET(GENMASK(29, 29), event.colour_space);

        pixmp_op->colorspace = V4L2_COLORSPACE_DEFAULT;
        pixmp_op->xfer_func = V4L2_XFER_FUNC_DEFAULT;
        pixmp_op->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
        pixmp_op->quantization = V4L2_QUANTIZATION_DEFAULT;

        if (video_signal_type_present_flag) {
                pixmp_op->quantization =
                        full_range ?
                        V4L2_QUANTIZATION_FULL_RANGE :
                        V4L2_QUANTIZATION_LIM_RANGE;
                if (colour_description_present_flag) {
                        pixmp_op->colorspace =
                                iris_hfi_get_v4l2_color_primaries(primaries);
                        pixmp_op->xfer_func =
                                iris_hfi_get_v4l2_transfer_char(transfer_char);
                        pixmp_op->ycbcr_enc =
                                iris_hfi_get_v4l2_matrix_coefficients(matrix_coeff);
                }
        }

        pixmp_ip->colorspace = pixmp_op->colorspace;
        pixmp_ip->xfer_func = pixmp_op->xfer_func;
        pixmp_ip->ycbcr_enc = pixmp_op->ycbcr_enc;
        pixmp_ip->quantization = pixmp_op->quantization;

        if (event.input_crop.width > 0 && event.input_crop.height > 0) {
                inst->crop.left = event.input_crop.left;
                inst->crop.top = event.input_crop.top;
                inst->crop.width = event.input_crop.width;
                inst->crop.height = event.input_crop.height;
        } else {
                inst->crop.left = 0;
                inst->crop.top = 0;
                inst->crop.width = event.width;
                inst->crop.height = event.height;
        }

        inst->fw_min_count = event.buf_count;
        inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT);
        inst->buffers[BUF_OUTPUT].size = pixmp_op->plane_fmt[0].sizeimage;
        ctrl = v4l2_ctrl_find(&inst->ctrl_handler, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
        if (ctrl)
                v4l2_ctrl_s_ctrl(ctrl, inst->buffers[BUF_OUTPUT].min_count);

        dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
        dst_q->min_reqbufs_allocation = inst->buffers[BUF_OUTPUT].min_count;

        if (event.bit_depth || !event.pic_struct) {
                dev_err(core->dev, "unsupported content, bit depth: %x, pic_struct = %x\n",
                        event.bit_depth, event.pic_struct);
                iris_inst_change_state(inst, IRIS_INST_ERROR);
        }
}

static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst,
                                            struct hfi_msg_event_notify_pkt *pkt)
{
        struct hfi_session_flush_pkt flush_pkt;
        u32 num_properties_changed;
        int ret;

        ret = iris_inst_sub_state_change_drc(inst);
        if (ret)
                return;

        switch (pkt->event_data1) {
        case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
        case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
                break;
        default:
                iris_inst_change_state(inst, IRIS_INST_ERROR);
                return;
        }

        num_properties_changed = pkt->event_data2;
        if (!num_properties_changed) {
                iris_inst_change_state(inst, IRIS_INST_ERROR);
                return;
        }

        iris_hfi_gen1_read_changed_params(inst, pkt);

        if (inst->state != IRIS_INST_ERROR && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) {

                flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt);
                flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH;
                flush_pkt.shdr.session_id = inst->session_id;
                flush_pkt.flush_type = HFI_FLUSH_OUTPUT;
                if (!iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size))
                        inst->flush_responses_pending++;
        }

        iris_vdec_src_change(inst);
        iris_inst_sub_state_change_drc_last(inst);
}

static void
iris_hfi_gen1_sys_event_notify(struct iris_core *core, void *packet)
{
        struct hfi_msg_event_notify_pkt *pkt = packet;
        struct iris_inst *instance;

        if (pkt->event_id == HFI_EVENT_SYS_ERROR)
                dev_err(core->dev, "sys error (type: %x, session id:%x, data1:%x, data2:%x)\n",
                        pkt->event_id, pkt->shdr.session_id, pkt->event_data1,
                        pkt->event_data2);

        core->state = IRIS_CORE_ERROR;

        mutex_lock(&core->lock);
        list_for_each_entry(instance, &core->instances, list)
                iris_inst_change_state(instance, IRIS_INST_ERROR);
        mutex_unlock(&core->lock);

        schedule_delayed_work(&core->sys_error_handler, msecs_to_jiffies(10));
}

static void
iris_hfi_gen1_event_session_error(struct iris_inst *inst, struct hfi_msg_event_notify_pkt *pkt)
{
        switch (pkt->event_data1) {
        /* non fatal session errors */
        case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
        case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
        case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
        case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
                dev_dbg(inst->core->dev, "session error: event id:%x, session id:%x\n",
                        pkt->event_data1, pkt->shdr.session_id);
                break;
        /* fatal session errors */
        default:
                /*
                 * firmware fills event_data2 as an additional information about the
                 * hfi command for which session error has ouccured.
                 */
                dev_err(inst->core->dev,
                        "session error for command: %x, event id:%x, session id:%x\n",
                        pkt->event_data2, pkt->event_data1,
                        pkt->shdr.session_id);
                iris_vb2_queue_error(inst);
                iris_inst_change_state(inst, IRIS_INST_ERROR);
                break;
        }
}

static void iris_hfi_gen1_session_event_notify(struct iris_inst *inst, void *packet)
{
        struct hfi_msg_event_notify_pkt *pkt = packet;

        switch (pkt->event_id) {
        case HFI_EVENT_SESSION_ERROR:
                iris_hfi_gen1_event_session_error(inst, pkt);
                break;
        case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
                iris_hfi_gen1_event_seq_changed(inst, pkt);
                break;
        default:
                break;
        }
}

static void iris_hfi_gen1_sys_init_done(struct iris_core *core, void *packet)
{
        struct hfi_msg_sys_init_done_pkt *pkt = packet;

        if (pkt->error_type != HFI_ERR_NONE) {
                core->state = IRIS_CORE_ERROR;
                return;
        }

        complete(&core->core_init_done);
}

static void
iris_hfi_gen1_sys_get_prop_image_version(struct iris_core *core,
                                         struct hfi_msg_sys_property_info_pkt *pkt)
{
        int req_bytes = pkt->hdr.size - sizeof(*pkt);
        char fw_version[IRIS_FW_VERSION_LENGTH];
        u8 *str_image_version;
        u32 i;

        if (req_bytes < IRIS_FW_VERSION_LENGTH - 1 || !pkt->data[0] || pkt->num_properties > 1) {
                dev_err(core->dev, "bad packet\n");
                return;
        }

        str_image_version = pkt->data;
        if (!str_image_version) {
                dev_err(core->dev, "firmware version not available\n");
                return;
        }

        for (i = 0; i < IRIS_FW_VERSION_LENGTH - 1; i++) {
                if (str_image_version[i] != '\0')
                        fw_version[i] = str_image_version[i];
                else
                        fw_version[i] = ' ';
        }
        fw_version[i] = '\0';
        dev_dbg(core->dev, "firmware version: %s\n", fw_version);
}

static void iris_hfi_gen1_sys_property_info(struct iris_core *core, void *packet)
{
        struct hfi_msg_sys_property_info_pkt *pkt = packet;

        if (!pkt->num_properties) {
                dev_dbg(core->dev, "no properties\n");
                return;
        }

        switch (pkt->property) {
        case HFI_PROPERTY_SYS_IMAGE_VERSION:
                iris_hfi_gen1_sys_get_prop_image_version(core, pkt);
                break;
        default:
                dev_dbg(core->dev, "unknown property data\n");
                break;
        }
}

static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet)
{
        struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
        struct v4l2_m2m_buffer *m2m_buffer, *n;
        struct iris_buffer *buf = NULL;
        bool found = false;

        /* EOS buffer sent via drain won't be in v4l2 buffer list */
        if (pkt->packet_buffer == 0xdeadb000)
                return;

        v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) {
                buf = to_iris_buffer(&m2m_buffer->vb);
                if (buf->index == pkt->input_tag) {
                        found = true;
                        break;
                }
        }
        if (!found)
                goto error;

        if (pkt->shdr.error_type == HFI_ERR_SESSION_UNSUPPORTED_STREAM) {
                buf->flags = V4L2_BUF_FLAG_ERROR;
                iris_vb2_queue_error(inst);
                iris_inst_change_state(inst, IRIS_INST_ERROR);
        }

        if (!(buf->attr & BUF_ATTR_QUEUED))
                return;

        buf->attr &= ~BUF_ATTR_QUEUED;

        if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
                buf->attr |= BUF_ATTR_BUFFER_DONE;
                iris_vb2_buffer_done(inst, buf);
        }

        return;

error:
        iris_inst_change_state(inst, IRIS_INST_ERROR);
        dev_err(inst->core->dev, "error in etb done\n");
}

static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet)
{
        struct hfi_msg_session_fbd_uncompressed_plane0_pkt *uncom_pkt = packet;
        struct hfi_msg_session_fbd_compressed_pkt *com_pkt = packet;
        struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
        struct v4l2_m2m_buffer *m2m_buffer, *n;
        struct hfi_session_flush_pkt flush_pkt;
        u32 timestamp_hi;
        u32 timestamp_lo;
        struct iris_core *core = inst->core;
        u32 filled_len;
        u32 pic_type;
        u32 output_tag;
        struct iris_buffer *buf, *iter;
        struct iris_buffers *buffers;
        u32 hfi_flags;
        u32 offset;
        u64 timestamp_us = 0;
        bool found = false;
        u32 flags = 0;

        if (inst->domain == DECODER) {
                timestamp_hi = uncom_pkt->time_stamp_hi;
                timestamp_lo = uncom_pkt->time_stamp_lo;
                filled_len = uncom_pkt->filled_len;
                pic_type = uncom_pkt->picture_type;
                output_tag = uncom_pkt->output_tag;
                hfi_flags = uncom_pkt->flags;
                offset = uncom_pkt->offset;
        } else {
                timestamp_hi = com_pkt->time_stamp_hi;
                timestamp_lo = com_pkt->time_stamp_lo;
                filled_len = com_pkt->filled_len;
                pic_type = com_pkt->picture_type;
                output_tag = com_pkt->output_tag;
                hfi_flags = com_pkt->flags;
                offset = com_pkt->offset;
        }

        if ((hfi_flags & HFI_BUFFERFLAG_EOS) && !filled_len) {
                reinit_completion(&inst->flush_completion);

                flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt);
                flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH;
                flush_pkt.shdr.session_id = inst->session_id;
                flush_pkt.flush_type = HFI_FLUSH_OUTPUT;
                if (!iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size))
                        inst->flush_responses_pending++;

                iris_inst_sub_state_change_drain_last(inst);
        }

        if (iris_split_mode_enabled(inst) && inst->domain == DECODER &&
            uncom_pkt->stream_id == 0) {
                buffers = &inst->buffers[BUF_DPB];
                if (!buffers)
                        goto error;

                found = false;
                list_for_each_entry(iter, &buffers->list, list) {
                        if (!(iter->attr & BUF_ATTR_QUEUED))
                                continue;

                        found = (iter->index == output_tag &&
                                iter->data_offset == offset);

                        if (found) {
                                buf = iter;
                                break;
                        }
                }
        } else {
                v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, m2m_buffer, n) {
                        buf = to_iris_buffer(&m2m_buffer->vb);
                        if (!(buf->attr & BUF_ATTR_QUEUED))
                                continue;

                        found = (buf->index == output_tag &&
                                 buf->data_offset == offset);

                        if (found)
                                break;
                }
        }
        if (!found)
                goto error;

        buf->data_offset = offset;
        buf->data_size = filled_len;

        if (filled_len) {
                timestamp_us = timestamp_hi;
                timestamp_us = (timestamp_us << 32) | timestamp_lo;
        } else {
                if (inst->domain == DECODER && uncom_pkt->stream_id == 1 &&
                    !inst->last_buffer_dequeued) {
                        if (iris_drc_pending(inst) || iris_drain_pending(inst)) {
                                flags |= V4L2_BUF_FLAG_LAST;
                                inst->last_buffer_dequeued = true;
                        }
                } else if (inst->domain == ENCODER) {
                        if (!inst->last_buffer_dequeued && iris_drain_pending(inst)) {
                                flags |= V4L2_BUF_FLAG_LAST;
                                inst->last_buffer_dequeued = true;
                        }
                }
        }
        buf->timestamp = timestamp_us;

        switch (pic_type) {
        case HFI_GEN1_PICTURE_IDR:
        case HFI_GEN1_PICTURE_I:
                flags |= V4L2_BUF_FLAG_KEYFRAME;
                break;
        case HFI_GEN1_PICTURE_P:
                flags |= V4L2_BUF_FLAG_PFRAME;
                break;
        case HFI_GEN1_PICTURE_B:
                flags |= V4L2_BUF_FLAG_BFRAME;
                break;
        case HFI_FRAME_NOTCODED:
        case HFI_UNUSED_PICT:
        case HFI_FRAME_YUV:
        default:
                break;
        }

        buf->attr &= ~BUF_ATTR_QUEUED;
        buf->attr |= BUF_ATTR_DEQUEUED;
        buf->attr |= BUF_ATTR_BUFFER_DONE;

        if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT)
                flags |= V4L2_BUF_FLAG_ERROR;

        if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME)
                flags |= V4L2_BUF_FLAG_ERROR;

        buf->flags |= flags;

        iris_vb2_buffer_done(inst, buf);

        return;

error:
        iris_inst_change_state(inst, IRIS_INST_ERROR);
        dev_err(core->dev, "error in ftb done\n");
}

struct iris_hfi_gen1_response_pkt_info {
        u32 pkt;
        u32 pkt_sz;
};

static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = {
        {
         .pkt = HFI_MSG_EVENT_NOTIFY,
         .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt),
        },
        {
         .pkt = HFI_MSG_SYS_INIT,
         .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt),
        },
        {
         .pkt = HFI_MSG_SYS_PROPERTY_INFO,
         .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt),
        },
        {
         .pkt = HFI_MSG_SYS_SESSION_INIT,
         .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt),
        },
        {
         .pkt = HFI_MSG_SYS_SESSION_END,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_LOAD_RESOURCES,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_START,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_STOP,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
         .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_FILL_BUFFER,
         .pkt_sz = sizeof(struct hfi_msg_session_fbd_compressed_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_FLUSH,
         .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
         .pkt_sz = sizeof(struct hfi_msg_session_hdr_pkt),
        },
        {
         .pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
         .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
        },
};

static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response)
{
        struct hfi_pkt_hdr *hdr = (struct hfi_pkt_hdr *)response;
        const struct iris_hfi_gen1_response_pkt_info *pkt_info;
        struct device *dev = core->dev;
        struct hfi_session_pkt *pkt;
        struct iris_inst *inst;
        bool found = false;
        u32 i;

        for (i = 0; i < ARRAY_SIZE(pkt_infos); i++) {
                pkt_info = &pkt_infos[i];
                if (pkt_info->pkt != hdr->pkt_type)
                        continue;
                found = true;
                break;
        }

        if (!found || hdr->size < pkt_info->pkt_sz) {
                dev_err(dev, "bad packet size (%d should be %d, pkt type:%x, found %d)\n",
                        hdr->size, pkt_info->pkt_sz, hdr->pkt_type, found);

                return;
        }

        switch (hdr->pkt_type) {
        case HFI_MSG_SYS_INIT:
                iris_hfi_gen1_sys_init_done(core, hdr);
                break;
        case HFI_MSG_SYS_PROPERTY_INFO:
                iris_hfi_gen1_sys_property_info(core, hdr);
                break;
        case HFI_MSG_EVENT_NOTIFY:
                pkt = (struct hfi_session_pkt *)hdr;
                inst = iris_get_instance(core, pkt->shdr.session_id);
                if (inst) {
                        mutex_lock(&inst->lock);
                        iris_hfi_gen1_session_event_notify(inst, hdr);
                        mutex_unlock(&inst->lock);
                } else {
                        iris_hfi_gen1_sys_event_notify(core, hdr);
                }

                break;
        default:
                pkt = (struct hfi_session_pkt *)hdr;
                inst = iris_get_instance(core, pkt->shdr.session_id);
                if (!inst) {
                        dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n",
                                 pkt->shdr.session_id,
                                 pkt_info ? pkt_info->pkt : 0);
                        return;
                }

                mutex_lock(&inst->lock);
                if (hdr->pkt_type == HFI_MSG_SESSION_EMPTY_BUFFER) {
                        iris_hfi_gen1_session_etb_done(inst, hdr);
                } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
                        iris_hfi_gen1_session_ftb_done(inst, hdr);
                } else {
                        struct hfi_msg_session_hdr_pkt *shdr;

                        shdr = (struct hfi_msg_session_hdr_pkt *)hdr;
                        if (shdr->error_type != HFI_ERR_NONE)
                                iris_inst_change_state(inst, IRIS_INST_ERROR);

                        if (pkt_info->pkt == HFI_MSG_SESSION_FLUSH) {
                                if (!(--inst->flush_responses_pending))
                                        complete(&inst->flush_completion);
                        } else {
                                complete(&inst->completion);
                        }
                }
                mutex_unlock(&inst->lock);

                break;
        }
}

static void iris_hfi_gen1_flush_debug_queue(struct iris_core *core, u8 *packet)
{
        struct hfi_msg_sys_coverage_pkt *pkt;

        while (!iris_hfi_queue_dbg_read(core, packet)) {
                pkt = (struct hfi_msg_sys_coverage_pkt *)packet;

                if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) {
                        struct hfi_msg_sys_debug_pkt *pkt =
                                (struct hfi_msg_sys_debug_pkt *)packet;

                        dev_dbg(core->dev, "%s", pkt->msg_data);
                }
        }
}

static void iris_hfi_gen1_response_handler(struct iris_core *core)
{
        memset(core->response_packet, 0, sizeof(struct hfi_pkt_hdr));
        while (!iris_hfi_queue_msg_read(core, core->response_packet)) {
                iris_hfi_gen1_handle_response(core, core->response_packet);
                memset(core->response_packet, 0, sizeof(struct hfi_pkt_hdr));
        }

        iris_hfi_gen1_flush_debug_queue(core, core->response_packet);
}

static const struct iris_hfi_response_ops iris_hfi_gen1_response_ops = {
        .hfi_response_handler = iris_hfi_gen1_response_handler,
};

void iris_hfi_gen1_response_ops_init(struct iris_core *core)
{
        core->hfi_response_ops = &iris_hfi_gen1_response_ops;
}