1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2017 Linaro Ltd.
5 */
6#include <linux/hash.h>
7#include <linux/list.h>
8#include <linux/slab.h>
9#include <linux/soc/qcom/smem.h>
10#include <media/videobuf2-v4l2.h>
11
12#include "core.h"
13#include "hfi.h"
14#include "hfi_helper.h"
15#include "hfi_msgs.h"
16#include "hfi_parser.h"
17
18#define SMEM_IMG_VER_TBL	469
19#define VER_STR_SZ		128
20#define SMEM_IMG_OFFSET_VENUS	(14 * 128)
21
22static void event_seq_changed(struct venus_core *core, struct venus_inst *inst,
23			      struct hfi_msg_event_notify_pkt *pkt)
24{
25	enum hfi_version ver = core->res->hfi_version;
26	struct hfi_event_data event = {0};
27	int num_properties_changed;
28	struct hfi_framesize *frame_sz;
29	struct hfi_profile_level *profile_level;
30	struct hfi_bit_depth *pixel_depth;
31	struct hfi_pic_struct *pic_struct;
32	struct hfi_colour_space *colour_info;
33	struct hfi_buffer_requirements *bufreq;
34	struct hfi_extradata_input_crop *crop;
35	struct hfi_dpb_counts *dpb_count;
36	u8 *data_ptr;
37	u32 ptype;
38
39	inst->error = HFI_ERR_NONE;
40
41	switch (pkt->event_data1) {
42	case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
43	case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
44		break;
45	default:
46		inst->error = HFI_ERR_SESSION_INVALID_PARAMETER;
47		goto done;
48	}
49
50	event.event_type = pkt->event_data1;
51
52	num_properties_changed = pkt->event_data2;
53	if (!num_properties_changed) {
54		inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
55		goto done;
56	}
57
58	data_ptr = (u8 *)&pkt->ext_event_data[0];
59	do {
60		ptype = *((u32 *)data_ptr);
61		switch (ptype) {
62		case HFI_PROPERTY_PARAM_FRAME_SIZE:
63			data_ptr += sizeof(u32);
64			frame_sz = (struct hfi_framesize *)data_ptr;
65			event.width = frame_sz->width;
66			event.height = frame_sz->height;
67			data_ptr += sizeof(*frame_sz);
68			break;
69		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
70			data_ptr += sizeof(u32);
71			profile_level = (struct hfi_profile_level *)data_ptr;
72			event.profile = profile_level->profile;
73			event.level = profile_level->level;
74			data_ptr += sizeof(*profile_level);
75			break;
76		case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
77			data_ptr += sizeof(u32);
78			pixel_depth = (struct hfi_bit_depth *)data_ptr;
79			event.bit_depth = pixel_depth->bit_depth;
80			data_ptr += sizeof(*pixel_depth);
81			break;
82		case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
83			data_ptr += sizeof(u32);
84			pic_struct = (struct hfi_pic_struct *)data_ptr;
85			event.pic_struct = pic_struct->progressive_only;
86			data_ptr += sizeof(*pic_struct);
87			break;
88		case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
89			data_ptr += sizeof(u32);
90			colour_info = (struct hfi_colour_space *)data_ptr;
91			event.colour_space = colour_info->colour_space;
92			data_ptr += sizeof(*colour_info);
93			break;
94		case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
95			data_ptr += sizeof(u32);
96			event.entropy_mode = *(u32 *)data_ptr;
97			data_ptr += sizeof(u32);
98			break;
99		case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
100			data_ptr += sizeof(u32);
101			bufreq = (struct hfi_buffer_requirements *)data_ptr;
102			event.buf_count = hfi_bufreq_get_count_min(bufreq, ver);
103			data_ptr += sizeof(*bufreq);
104			break;
105		case HFI_INDEX_EXTRADATA_INPUT_CROP:
106			data_ptr += sizeof(u32);
107			crop = (struct hfi_extradata_input_crop *)data_ptr;
108			event.input_crop.left = crop->left;
109			event.input_crop.top = crop->top;
110			event.input_crop.width = crop->width;
111			event.input_crop.height = crop->height;
112			data_ptr += sizeof(*crop);
113			break;
114		case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS:
115			data_ptr += sizeof(u32);
116			dpb_count = (struct hfi_dpb_counts *)data_ptr;
117			event.buf_count = dpb_count->fw_min_cnt;
118			data_ptr += sizeof(*dpb_count);
119			break;
120		default:
121			break;
122		}
123		num_properties_changed--;
124	} while (num_properties_changed > 0);
125
126done:
127	inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
128}
129
130static void event_release_buffer_ref(struct venus_core *core,
131				     struct venus_inst *inst,
132				     struct hfi_msg_event_notify_pkt *pkt)
133{
134	struct hfi_event_data event = {0};
135	struct hfi_msg_event_release_buffer_ref_pkt *data;
136
137	data = (struct hfi_msg_event_release_buffer_ref_pkt *)
138		pkt->ext_event_data;
139
140	event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE;
141	event.packet_buffer = data->packet_buffer;
142	event.extradata_buffer = data->extradata_buffer;
143	event.tag = data->output_tag;
144
145	inst->error = HFI_ERR_NONE;
146	inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
147}
148
149static void event_sys_error(struct venus_core *core, u32 event,
150			    struct hfi_msg_event_notify_pkt *pkt)
151{
152	if (pkt)
153		dev_dbg(core->dev, VDBGH
154			"sys error (session id:%x, data1:%x, data2:%x)\n",
155			pkt->shdr.session_id, pkt->event_data1,
156			pkt->event_data2);
157
158	core->core_ops->event_notify(core, event);
159}
160
161static void
162event_session_error(struct venus_core *core, struct venus_inst *inst,
163		    struct hfi_msg_event_notify_pkt *pkt)
164{
165	struct device *dev = core->dev;
166
167	dev_dbg(dev, VDBGH "session error: event id:%x, session id:%x\n",
168		pkt->event_data1, pkt->shdr.session_id);
169
170	if (!inst)
171		return;
172
173	switch (pkt->event_data1) {
174	/* non fatal session errors */
175	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
176	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
177	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
178	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
179		inst->error = HFI_ERR_NONE;
180		break;
181	default:
182		dev_err(dev, "session error: event id:%x (%x), session id:%x\n",
183			pkt->event_data1, pkt->event_data2,
184			pkt->shdr.session_id);
185
186		inst->error = pkt->event_data1;
187		inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL);
188		break;
189	}
190}
191
192static void hfi_event_notify(struct venus_core *core, struct venus_inst *inst,
193			     void *packet)
194{
195	struct hfi_msg_event_notify_pkt *pkt = packet;
196
197	if (!packet)
198		return;
199
200	switch (pkt->event_id) {
201	case HFI_EVENT_SYS_ERROR:
202		event_sys_error(core, EVT_SYS_ERROR, pkt);
203		break;
204	case HFI_EVENT_SESSION_ERROR:
205		event_session_error(core, inst, pkt);
206		break;
207	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
208		event_seq_changed(core, inst, pkt);
209		break;
210	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
211		event_release_buffer_ref(core, inst, pkt);
212		break;
213	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
214		break;
215	default:
216		break;
217	}
218}
219
220static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst,
221			      void *packet)
222{
223	struct hfi_msg_sys_init_done_pkt *pkt = packet;
224	int rem_bytes;
225	u32 error;
226
227	error = pkt->error_type;
228	if (error != HFI_ERR_NONE)
229		goto done;
230
231	if (!pkt->num_properties) {
232		error = HFI_ERR_SYS_INVALID_PARAMETER;
233		goto done;
234	}
235
236	rem_bytes = pkt->hdr.size - sizeof(*pkt);
237	if (rem_bytes <= 0) {
238		/* missing property data */
239		error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
240		goto done;
241	}
242
243	error = hfi_parser(core, inst, pkt->data, rem_bytes);
244
245done:
246	core->error = error;
247	complete(&core->done);
248}
249
250static void
251sys_get_prop_image_version(struct venus_core *core,
252			   struct hfi_msg_sys_property_info_pkt *pkt)
253{
254	struct device *dev = core->dev;
255	u8 *smem_tbl_ptr;
256	u8 *img_ver;
257	int req_bytes;
258	size_t smem_blk_sz;
259	int ret;
260
261	req_bytes = pkt->hdr.size - sizeof(*pkt);
262
263	if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1)
264		/* bad packet */
265		return;
266
267	img_ver = pkt->data;
268	if (!img_ver)
269		return;
270
271	ret = sscanf(img_ver, "14:video-firmware.%u.%u-%u",
272		     &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
273	if (ret)
274		goto done;
275
276	ret = sscanf(img_ver, "14:VIDEO.VPU.%u.%u-%u",
277		     &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
278	if (ret)
279		goto done;
280
281	ret = sscanf(img_ver, "14:VIDEO.VE.%u.%u-%u",
282		     &core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
283	if (ret)
284		goto done;
285
286	dev_err(dev, VDBGL "error reading F/W version\n");
287	return;
288
289done:
290	dev_dbg(dev, VDBGL "F/W version: %s, major %u, minor %u, revision %u\n",
291		img_ver, core->venus_ver.major, core->venus_ver.minor, core->venus_ver.rev);
292
293	smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY,
294		SMEM_IMG_VER_TBL, &smem_blk_sz);
295	if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ)
296		memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS,
297		       img_ver, VER_STR_SZ);
298}
299
300static void hfi_sys_property_info(struct venus_core *core,
301				  struct venus_inst *inst, void *packet)
302{
303	struct hfi_msg_sys_property_info_pkt *pkt = packet;
304	struct device *dev = core->dev;
305
306	if (!pkt->num_properties) {
307		dev_dbg(dev, VDBGL "no properties\n");
308		return;
309	}
310
311	switch (pkt->property) {
312	case HFI_PROPERTY_SYS_IMAGE_VERSION:
313		sys_get_prop_image_version(core, pkt);
314		break;
315	default:
316		dev_dbg(dev, VDBGL "unknown property data\n");
317		break;
318	}
319}
320
321static void hfi_sys_rel_resource_done(struct venus_core *core,
322				      struct venus_inst *inst,
323				      void *packet)
324{
325	struct hfi_msg_sys_release_resource_done_pkt *pkt = packet;
326
327	core->error = pkt->error_type;
328	complete(&core->done);
329}
330
331static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst,
332			      void *packet)
333{
334	struct hfi_msg_sys_ping_ack_pkt *pkt = packet;
335
336	core->error = HFI_ERR_NONE;
337
338	if (pkt->client_data != 0xbeef)
339		core->error = HFI_ERR_SYS_FATAL;
340
341	complete(&core->done);
342}
343
344static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst,
345			      void *packet)
346{
347	dev_dbg(core->dev, VDBGL "sys idle\n");
348}
349
350static void hfi_sys_pc_prepare_done(struct venus_core *core,
351				    struct venus_inst *inst, void *packet)
352{
353	struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet;
354
355	dev_dbg(core->dev, VDBGL "pc prepare done (error %x)\n",
356		pkt->error_type);
357}
358
359static unsigned int
360session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
361			       struct hfi_profile_level *profile_level)
362{
363	struct hfi_profile_level *hfi;
364	u32 req_bytes;
365
366	req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
367
368	if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level))
369		/* bad packet */
370		return HFI_ERR_SESSION_INVALID_PARAMETER;
371
372	hfi = (struct hfi_profile_level *)&pkt->data[0];
373	profile_level->profile = hfi->profile;
374	profile_level->level = hfi->level;
375
376	return HFI_ERR_NONE;
377}
378
379static unsigned int
380session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
381			 struct hfi_buffer_requirements *bufreq)
382{
383	struct hfi_buffer_requirements *buf_req;
384	u32 req_bytes;
385	unsigned int idx = 0;
386
387	req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
388
389	if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0])
390		/* bad packet */
391		return HFI_ERR_SESSION_INVALID_PARAMETER;
392
393	buf_req = (struct hfi_buffer_requirements *)&pkt->data[0];
394	if (!buf_req)
395		return HFI_ERR_SESSION_INVALID_PARAMETER;
396
397	while (req_bytes) {
398		memcpy(&bufreq[idx], buf_req, sizeof(*bufreq));
399		idx++;
400
401		if (idx >= HFI_BUFFER_TYPE_MAX)
402			return HFI_ERR_SESSION_INVALID_PARAMETER;
403
404		req_bytes -= sizeof(struct hfi_buffer_requirements);
405		buf_req++;
406	}
407
408	return HFI_ERR_NONE;
409}
410
411static void hfi_session_prop_info(struct venus_core *core,
412				  struct venus_inst *inst, void *packet)
413{
414	struct hfi_msg_session_property_info_pkt *pkt = packet;
415	struct device *dev = core->dev;
416	union hfi_get_property *hprop = &inst->hprop;
417	unsigned int error = HFI_ERR_NONE;
418
419	if (!pkt->num_properties) {
420		error = HFI_ERR_SESSION_INVALID_PARAMETER;
421		dev_err(dev, "%s: no properties\n", __func__);
422		goto done;
423	}
424
425	switch (pkt->property) {
426	case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
427		memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
428		error = session_get_prop_buf_req(pkt, hprop->bufreq);
429		break;
430	case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
431		memset(&hprop->profile_level, 0, sizeof(hprop->profile_level));
432		error = session_get_prop_profile_level(pkt,
433						       &hprop->profile_level);
434		break;
435	case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
436		break;
437	default:
438		dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property);
439		return;
440	}
441
442done:
443	inst->error = error;
444	complete(&inst->done);
445}
446
447static void hfi_session_init_done(struct venus_core *core,
448				  struct venus_inst *inst, void *packet)
449{
450	struct hfi_msg_session_init_done_pkt *pkt = packet;
451	int rem_bytes;
452	u32 error;
453
454	error = pkt->error_type;
455	if (error != HFI_ERR_NONE)
456		goto done;
457
458	if (!IS_V1(core))
459		goto done;
460
461	rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
462	if (rem_bytes <= 0) {
463		error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
464		goto done;
465	}
466
467	error = hfi_parser(core, inst, pkt->data, rem_bytes);
468done:
469	inst->error = error;
470	complete(&inst->done);
471}
472
473static void hfi_session_load_res_done(struct venus_core *core,
474				      struct venus_inst *inst, void *packet)
475{
476	struct hfi_msg_session_load_resources_done_pkt *pkt = packet;
477
478	inst->error = pkt->error_type;
479	complete(&inst->done);
480}
481
482static void hfi_session_flush_done(struct venus_core *core,
483				   struct venus_inst *inst, void *packet)
484{
485	struct hfi_msg_session_flush_done_pkt *pkt = packet;
486
487	inst->error = pkt->error_type;
488	complete(&inst->done);
489	if (inst->ops->flush_done)
490		inst->ops->flush_done(inst);
491}
492
493static void hfi_session_etb_done(struct venus_core *core,
494				 struct venus_inst *inst, void *packet)
495{
496	struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
497
498	inst->error = pkt->error_type;
499	inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag,
500			    pkt->filled_len, pkt->offset, 0, 0, 0);
501}
502
503static void hfi_session_ftb_done(struct venus_core *core,
504				 struct venus_inst *inst, void *packet)
505{
506	u32 session_type = inst->session_type;
507	u64 timestamp_us = 0;
508	u32 timestamp_hi = 0, timestamp_lo = 0;
509	unsigned int error;
510	u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0;
511	u32 pic_type = 0, buffer_type = 0, output_tag = -1;
512
513	if (session_type == VIDC_SESSION_TYPE_ENC) {
514		struct hfi_msg_session_fbd_compressed_pkt *pkt = packet;
515
516		timestamp_hi = pkt->time_stamp_hi;
517		timestamp_lo = pkt->time_stamp_lo;
518		hfi_flags = pkt->flags;
519		offset = pkt->offset;
520		filled_len = pkt->filled_len;
521		pic_type = pkt->picture_type;
522		output_tag = pkt->output_tag;
523		buffer_type = HFI_BUFFER_OUTPUT;
524
525		error = pkt->error_type;
526	} else if (session_type == VIDC_SESSION_TYPE_DEC) {
527		struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt =
528			packet;
529
530		timestamp_hi = pkt->time_stamp_hi;
531		timestamp_lo = pkt->time_stamp_lo;
532		hfi_flags = pkt->flags;
533		offset = pkt->offset;
534		filled_len = pkt->filled_len;
535		pic_type = pkt->picture_type;
536		output_tag = pkt->output_tag;
537
538		if (pkt->stream_id == 0)
539			buffer_type = HFI_BUFFER_OUTPUT;
540		else if (pkt->stream_id == 1)
541			buffer_type = HFI_BUFFER_OUTPUT2;
542
543		error = pkt->error_type;
544	} else {
545		error = HFI_ERR_SESSION_INVALID_PARAMETER;
546	}
547
548	if (buffer_type != HFI_BUFFER_OUTPUT &&
549	    buffer_type != HFI_BUFFER_OUTPUT2)
550		goto done;
551
552	if (hfi_flags & HFI_BUFFERFLAG_EOS)
553		flags |= V4L2_BUF_FLAG_LAST;
554
555	switch (pic_type) {
556	case HFI_PICTURE_IDR:
557	case HFI_PICTURE_I:
558		flags |= V4L2_BUF_FLAG_KEYFRAME;
559		break;
560	case HFI_PICTURE_P:
561		flags |= V4L2_BUF_FLAG_PFRAME;
562		break;
563	case HFI_PICTURE_B:
564		flags |= V4L2_BUF_FLAG_BFRAME;
565		break;
566	case HFI_FRAME_NOTCODED:
567	case HFI_UNUSED_PICT:
568	case HFI_FRAME_YUV:
569	default:
570		break;
571	}
572
573	if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) {
574		timestamp_us = timestamp_hi;
575		timestamp_us = (timestamp_us << 32) | timestamp_lo;
576	}
577
578done:
579	inst->error = error;
580	inst->ops->buf_done(inst, buffer_type, output_tag, filled_len,
581			    offset, flags, hfi_flags, timestamp_us);
582}
583
584static void hfi_session_start_done(struct venus_core *core,
585				   struct venus_inst *inst, void *packet)
586{
587	struct hfi_msg_session_start_done_pkt *pkt = packet;
588
589	inst->error = pkt->error_type;
590	complete(&inst->done);
591}
592
593static void hfi_session_stop_done(struct venus_core *core,
594				  struct venus_inst *inst, void *packet)
595{
596	struct hfi_msg_session_stop_done_pkt *pkt = packet;
597
598	inst->error = pkt->error_type;
599	complete(&inst->done);
600}
601
602static void hfi_session_rel_res_done(struct venus_core *core,
603				     struct venus_inst *inst, void *packet)
604{
605	struct hfi_msg_session_release_resources_done_pkt *pkt = packet;
606
607	inst->error = pkt->error_type;
608	complete(&inst->done);
609}
610
611static void hfi_session_rel_buf_done(struct venus_core *core,
612				     struct venus_inst *inst, void *packet)
613{
614	struct hfi_msg_session_release_buffers_done_pkt *pkt = packet;
615
616	inst->error = pkt->error_type;
617	complete(&inst->done);
618}
619
620static void hfi_session_end_done(struct venus_core *core,
621				 struct venus_inst *inst, void *packet)
622{
623	struct hfi_msg_session_end_done_pkt *pkt = packet;
624
625	inst->error = pkt->error_type;
626	complete(&inst->done);
627}
628
629static void hfi_session_abort_done(struct venus_core *core,
630				   struct venus_inst *inst, void *packet)
631{
632	struct hfi_msg_sys_session_abort_done_pkt *pkt = packet;
633
634	inst->error = pkt->error_type;
635	complete(&inst->done);
636}
637
638static void hfi_session_get_seq_hdr_done(struct venus_core *core,
639					 struct venus_inst *inst, void *packet)
640{
641	struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet;
642
643	inst->error = pkt->error_type;
644	complete(&inst->done);
645}
646
647struct hfi_done_handler {
648	u32 pkt;
649	u32 pkt_sz;
650	u32 pkt_sz2;
651	void (*done)(struct venus_core *, struct venus_inst *, void *);
652	bool is_sys_pkt;
653};
654
655static const struct hfi_done_handler handlers[] = {
656	{.pkt = HFI_MSG_EVENT_NOTIFY,
657	 .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt),
658	 .done = hfi_event_notify,
659	},
660	{.pkt = HFI_MSG_SYS_INIT,
661	 .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt),
662	 .done = hfi_sys_init_done,
663	 .is_sys_pkt = true,
664	},
665	{.pkt = HFI_MSG_SYS_PROPERTY_INFO,
666	 .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt),
667	 .done = hfi_sys_property_info,
668	 .is_sys_pkt = true,
669	},
670	{.pkt = HFI_MSG_SYS_RELEASE_RESOURCE,
671	 .pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt),
672	 .done = hfi_sys_rel_resource_done,
673	 .is_sys_pkt = true,
674	},
675	{.pkt = HFI_MSG_SYS_PING_ACK,
676	 .pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt),
677	 .done = hfi_sys_ping_done,
678	 .is_sys_pkt = true,
679	},
680	{.pkt = HFI_MSG_SYS_IDLE,
681	 .pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt),
682	 .done = hfi_sys_idle_done,
683	 .is_sys_pkt = true,
684	},
685	{.pkt = HFI_MSG_SYS_PC_PREP,
686	 .pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt),
687	 .done = hfi_sys_pc_prepare_done,
688	 .is_sys_pkt = true,
689	},
690	{.pkt = HFI_MSG_SYS_SESSION_INIT,
691	 .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt),
692	 .done = hfi_session_init_done,
693	},
694	{.pkt = HFI_MSG_SYS_SESSION_END,
695	 .pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt),
696	 .done = hfi_session_end_done,
697	},
698	{.pkt = HFI_MSG_SESSION_LOAD_RESOURCES,
699	 .pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt),
700	 .done = hfi_session_load_res_done,
701	},
702	{.pkt = HFI_MSG_SESSION_START,
703	 .pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt),
704	 .done = hfi_session_start_done,
705	},
706	{.pkt = HFI_MSG_SESSION_STOP,
707	 .pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt),
708	 .done = hfi_session_stop_done,
709	},
710	{.pkt = HFI_MSG_SYS_SESSION_ABORT,
711	 .pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt),
712	 .done = hfi_session_abort_done,
713	},
714	{.pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
715	 .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
716	 .done = hfi_session_etb_done,
717	},
718	{.pkt = HFI_MSG_SESSION_FILL_BUFFER,
719	 .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt),
720	 .pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt),
721	 .done = hfi_session_ftb_done,
722	},
723	{.pkt = HFI_MSG_SESSION_FLUSH,
724	 .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
725	 .done = hfi_session_flush_done,
726	},
727	{.pkt = HFI_MSG_SESSION_PROPERTY_INFO,
728	 .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt),
729	 .done = hfi_session_prop_info,
730	},
731	{.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
732	 .pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt),
733	 .done = hfi_session_rel_res_done,
734	},
735	{.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER,
736	 .pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt),
737	 .done = hfi_session_get_seq_hdr_done,
738	},
739	{.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
740	 .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
741	 .done = hfi_session_rel_buf_done,
742	},
743};
744
745void hfi_process_watchdog_timeout(struct venus_core *core)
746{
747	event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL);
748}
749
750static struct venus_inst *to_instance(struct venus_core *core, u32 session_id)
751{
752	struct venus_inst *inst;
753
754	mutex_lock(&core->lock);
755	list_for_each_entry(inst, &core->instances, list)
756		if (hash32_ptr(inst) == session_id) {
757			mutex_unlock(&core->lock);
758			return inst;
759		}
760	mutex_unlock(&core->lock);
761
762	return NULL;
763}
764
765u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr)
766{
767	const struct hfi_done_handler *handler;
768	struct device *dev = core->dev;
769	struct venus_inst *inst;
770	bool found = false;
771	unsigned int i;
772
773	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
774		handler = &handlers[i];
775		if (handler->pkt != hdr->pkt_type)
776			continue;
777		found = true;
778		break;
779	}
780
781	if (!found)
782		return hdr->pkt_type;
783
784	if (hdr->size && hdr->size < handler->pkt_sz &&
785	    hdr->size < handler->pkt_sz2) {
786		dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n",
787			hdr->size, handler->pkt_sz, hdr->pkt_type);
788
789		return hdr->pkt_type;
790	}
791
792	if (handler->is_sys_pkt) {
793		inst = NULL;
794	} else {
795		struct hfi_session_pkt *pkt;
796
797		pkt = (struct hfi_session_pkt *)hdr;
798		inst = to_instance(core, pkt->shdr.session_id);
799
800		if (!inst)
801			dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n",
802				 pkt->shdr.session_id,
803				 handler ? handler->pkt : 0);
804
805		/*
806		 * Event of type HFI_EVENT_SYS_ERROR will not have any session
807		 * associated with it
808		 */
809		if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) {
810			dev_err(dev, "got invalid session id:%x\n",
811				pkt->shdr.session_id);
812			goto invalid_session;
813		}
814	}
815
816	handler->done(core, inst, hdr);
817
818invalid_session:
819	return hdr->pkt_type;
820}
821