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