1 /*
2  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
3  * Copyright (C) 2017 Linaro Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 and
7  * only version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 #include <linux/hash.h>
16 #include <linux/list.h>
17 #include <linux/slab.h>
18 #include <media/videobuf2-v4l2.h>
19 
20 #include "core.h"
21 #include "hfi.h"
22 #include "hfi_helper.h"
23 #include "hfi_msgs.h"
24 
25 static void event_seq_changed(struct venus_core *core, struct venus_inst *inst,
26 			      struct hfi_msg_event_notify_pkt *pkt)
27 {
28 	struct hfi_event_data event = {0};
29 	int num_properties_changed;
30 	struct hfi_framesize *frame_sz;
31 	struct hfi_profile_level *profile_level;
32 	u8 *data_ptr;
33 	u32 ptype;
34 
35 	inst->error = HFI_ERR_NONE;
36 
37 	switch (pkt->event_data1) {
38 	case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
39 	case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
40 		break;
41 	default:
42 		inst->error = HFI_ERR_SESSION_INVALID_PARAMETER;
43 		goto done;
44 	}
45 
46 	event.event_type = pkt->event_data1;
47 
48 	num_properties_changed = pkt->event_data2;
49 	if (!num_properties_changed) {
50 		inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
51 		goto done;
52 	}
53 
54 	data_ptr = (u8 *)&pkt->ext_event_data[0];
55 	do {
56 		ptype = *((u32 *)data_ptr);
57 		switch (ptype) {
58 		case HFI_PROPERTY_PARAM_FRAME_SIZE:
59 			data_ptr += sizeof(u32);
60 			frame_sz = (struct hfi_framesize *)data_ptr;
61 			event.width = frame_sz->width;
62 			event.height = frame_sz->height;
63 			data_ptr += sizeof(frame_sz);
64 			break;
65 		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
66 			data_ptr += sizeof(u32);
67 			profile_level = (struct hfi_profile_level *)data_ptr;
68 			event.profile = profile_level->profile;
69 			event.level = profile_level->level;
70 			data_ptr += sizeof(profile_level);
71 			break;
72 		default:
73 			break;
74 		}
75 		num_properties_changed--;
76 	} while (num_properties_changed > 0);
77 
78 done:
79 	inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
80 }
81 
82 static void event_release_buffer_ref(struct venus_core *core,
83 				     struct venus_inst *inst,
84 				     struct hfi_msg_event_notify_pkt *pkt)
85 {
86 	struct hfi_event_data event = {0};
87 	struct hfi_msg_event_release_buffer_ref_pkt *data;
88 
89 	data = (struct hfi_msg_event_release_buffer_ref_pkt *)
90 		pkt->ext_event_data;
91 
92 	event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE;
93 	event.packet_buffer = data->packet_buffer;
94 	event.extradata_buffer = data->extradata_buffer;
95 	event.tag = data->output_tag;
96 
97 	inst->error = HFI_ERR_NONE;
98 	inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
99 }
100 
101 static void event_sys_error(struct venus_core *core, u32 event,
102 			    struct hfi_msg_event_notify_pkt *pkt)
103 {
104 	if (pkt)
105 		dev_dbg(core->dev,
106 			"sys error (session id:%x, data1:%x, data2:%x)\n",
107 			pkt->shdr.session_id, pkt->event_data1,
108 			pkt->event_data2);
109 
110 	core->core_ops->event_notify(core, event);
111 }
112 
113 static void
114 event_session_error(struct venus_core *core, struct venus_inst *inst,
115 		    struct hfi_msg_event_notify_pkt *pkt)
116 {
117 	struct device *dev = core->dev;
118 
119 	dev_dbg(dev, "session error: event id:%x, session id:%x\n",
120 		pkt->event_data1, pkt->shdr.session_id);
121 
122 	if (!inst)
123 		return;
124 
125 	switch (pkt->event_data1) {
126 	/* non fatal session errors */
127 	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
128 	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
129 	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
130 	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
131 		inst->error = HFI_ERR_NONE;
132 		break;
133 	default:
134 		dev_err(dev, "session error: event id:%x (%x), session id:%x\n",
135 			pkt->event_data1, pkt->event_data2,
136 			pkt->shdr.session_id);
137 
138 		inst->error = pkt->event_data1;
139 		inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL);
140 		break;
141 	}
142 }
143 
144 static void hfi_event_notify(struct venus_core *core, struct venus_inst *inst,
145 			     void *packet)
146 {
147 	struct hfi_msg_event_notify_pkt *pkt = packet;
148 
149 	if (!packet)
150 		return;
151 
152 	switch (pkt->event_id) {
153 	case HFI_EVENT_SYS_ERROR:
154 		event_sys_error(core, EVT_SYS_ERROR, pkt);
155 		break;
156 	case HFI_EVENT_SESSION_ERROR:
157 		event_session_error(core, inst, pkt);
158 		break;
159 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
160 		event_seq_changed(core, inst, pkt);
161 		break;
162 	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
163 		event_release_buffer_ref(core, inst, pkt);
164 		break;
165 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
166 		break;
167 	default:
168 		break;
169 	}
170 }
171 
172 static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst,
173 			      void *packet)
174 {
175 	struct hfi_msg_sys_init_done_pkt *pkt = packet;
176 	u32 rem_bytes, read_bytes = 0, num_properties;
177 	u32 error, ptype;
178 	u8 *data;
179 
180 	error = pkt->error_type;
181 	if (error != HFI_ERR_NONE)
182 		goto err_no_prop;
183 
184 	num_properties = pkt->num_properties;
185 
186 	if (!num_properties) {
187 		error = HFI_ERR_SYS_INVALID_PARAMETER;
188 		goto err_no_prop;
189 	}
190 
191 	rem_bytes = pkt->hdr.size - sizeof(*pkt) + sizeof(u32);
192 
193 	if (!rem_bytes) {
194 		/* missing property data */
195 		error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
196 		goto err_no_prop;
197 	}
198 
199 	data = (u8 *)&pkt->data[0];
200 
201 	if (core->res->hfi_version == HFI_VERSION_3XX)
202 		goto err_no_prop;
203 
204 	while (num_properties && rem_bytes >= sizeof(u32)) {
205 		ptype = *((u32 *)data);
206 		data += sizeof(u32);
207 
208 		switch (ptype) {
209 		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: {
210 			struct hfi_codec_supported *prop;
211 
212 			prop = (struct hfi_codec_supported *)data;
213 
214 			if (rem_bytes < sizeof(*prop)) {
215 				error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
216 				break;
217 			}
218 
219 			read_bytes += sizeof(*prop) + sizeof(u32);
220 			core->dec_codecs = prop->dec_codecs;
221 			core->enc_codecs = prop->enc_codecs;
222 			break;
223 		}
224 		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED: {
225 			struct hfi_max_sessions_supported *prop;
226 
227 			if (rem_bytes < sizeof(*prop)) {
228 				error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
229 				break;
230 			}
231 
232 			prop = (struct hfi_max_sessions_supported *)data;
233 			read_bytes += sizeof(*prop) + sizeof(u32);
234 			core->max_sessions_supported = prop->max_sessions;
235 			break;
236 		}
237 		default:
238 			error = HFI_ERR_SYS_INVALID_PARAMETER;
239 			break;
240 		}
241 
242 		if (error)
243 			break;
244 
245 		rem_bytes -= read_bytes;
246 		data += read_bytes;
247 		num_properties--;
248 	}
249 
250 err_no_prop:
251 	core->error = error;
252 	complete(&core->done);
253 }
254 
255 static void
256 sys_get_prop_image_version(struct device *dev,
257 			   struct hfi_msg_sys_property_info_pkt *pkt)
258 {
259 	int req_bytes;
260 
261 	req_bytes = pkt->hdr.size - sizeof(*pkt);
262 
263 	if (req_bytes < 128 || !pkt->data[1] || pkt->num_properties > 1)
264 		/* bad packet */
265 		return;
266 
267 	dev_dbg(dev, "F/W version: %s\n", (u8 *)&pkt->data[1]);
268 }
269 
270 static void hfi_sys_property_info(struct venus_core *core,
271 				  struct venus_inst *inst, void *packet)
272 {
273 	struct hfi_msg_sys_property_info_pkt *pkt = packet;
274 	struct device *dev = core->dev;
275 
276 	if (!pkt->num_properties) {
277 		dev_dbg(dev, "%s: no properties\n", __func__);
278 		return;
279 	}
280 
281 	switch (pkt->data[0]) {
282 	case HFI_PROPERTY_SYS_IMAGE_VERSION:
283 		sys_get_prop_image_version(dev, pkt);
284 		break;
285 	default:
286 		dev_dbg(dev, "%s: unknown property data\n", __func__);
287 		break;
288 	}
289 }
290 
291 static void hfi_sys_rel_resource_done(struct venus_core *core,
292 				      struct venus_inst *inst,
293 				      void *packet)
294 {
295 	struct hfi_msg_sys_release_resource_done_pkt *pkt = packet;
296 
297 	core->error = pkt->error_type;
298 	complete(&core->done);
299 }
300 
301 static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst,
302 			      void *packet)
303 {
304 	struct hfi_msg_sys_ping_ack_pkt *pkt = packet;
305 
306 	core->error = HFI_ERR_NONE;
307 
308 	if (pkt->client_data != 0xbeef)
309 		core->error = HFI_ERR_SYS_FATAL;
310 
311 	complete(&core->done);
312 }
313 
314 static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst,
315 			      void *packet)
316 {
317 	dev_dbg(core->dev, "sys idle\n");
318 }
319 
320 static void hfi_sys_pc_prepare_done(struct venus_core *core,
321 				    struct venus_inst *inst, void *packet)
322 {
323 	struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet;
324 
325 	dev_dbg(core->dev, "pc prepare done (error %x)\n", pkt->error_type);
326 }
327 
328 static void
329 hfi_copy_cap_prop(struct hfi_capability *in, struct venus_inst *inst)
330 {
331 	if (!in || !inst)
332 		return;
333 
334 	switch (in->capability_type) {
335 	case HFI_CAPABILITY_FRAME_WIDTH:
336 		inst->cap_width = *in;
337 		break;
338 	case HFI_CAPABILITY_FRAME_HEIGHT:
339 		inst->cap_height = *in;
340 		break;
341 	case HFI_CAPABILITY_MBS_PER_FRAME:
342 		inst->cap_mbs_per_frame = *in;
343 		break;
344 	case HFI_CAPABILITY_MBS_PER_SECOND:
345 		inst->cap_mbs_per_sec = *in;
346 		break;
347 	case HFI_CAPABILITY_FRAMERATE:
348 		inst->cap_framerate = *in;
349 		break;
350 	case HFI_CAPABILITY_SCALE_X:
351 		inst->cap_scale_x = *in;
352 		break;
353 	case HFI_CAPABILITY_SCALE_Y:
354 		inst->cap_scale_y = *in;
355 		break;
356 	case HFI_CAPABILITY_BITRATE:
357 		inst->cap_bitrate = *in;
358 		break;
359 	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
360 		inst->cap_hier_p = *in;
361 		break;
362 	case HFI_CAPABILITY_ENC_LTR_COUNT:
363 		inst->cap_ltr_count = *in;
364 		break;
365 	case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
366 		inst->cap_secure_output2_threshold = *in;
367 		break;
368 	default:
369 		break;
370 	}
371 }
372 
373 static unsigned int
374 session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
375 			       struct hfi_profile_level *profile_level)
376 {
377 	struct hfi_profile_level *hfi;
378 	u32 req_bytes;
379 
380 	req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
381 
382 	if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level))
383 		/* bad packet */
384 		return HFI_ERR_SESSION_INVALID_PARAMETER;
385 
386 	hfi = (struct hfi_profile_level *)&pkt->data[1];
387 	profile_level->profile = hfi->profile;
388 	profile_level->level = hfi->level;
389 
390 	return HFI_ERR_NONE;
391 }
392 
393 static unsigned int
394 session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
395 			 struct hfi_buffer_requirements *bufreq)
396 {
397 	struct hfi_buffer_requirements *buf_req;
398 	u32 req_bytes;
399 	unsigned int idx = 0;
400 
401 	req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
402 
403 	if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1])
404 		/* bad packet */
405 		return HFI_ERR_SESSION_INVALID_PARAMETER;
406 
407 	buf_req = (struct hfi_buffer_requirements *)&pkt->data[1];
408 	if (!buf_req)
409 		return HFI_ERR_SESSION_INVALID_PARAMETER;
410 
411 	while (req_bytes) {
412 		memcpy(&bufreq[idx], buf_req, sizeof(*bufreq));
413 		idx++;
414 
415 		if (idx > HFI_BUFFER_TYPE_MAX)
416 			return HFI_ERR_SESSION_INVALID_PARAMETER;
417 
418 		req_bytes -= sizeof(struct hfi_buffer_requirements);
419 		buf_req++;
420 	}
421 
422 	return HFI_ERR_NONE;
423 }
424 
425 static void hfi_session_prop_info(struct venus_core *core,
426 				  struct venus_inst *inst, void *packet)
427 {
428 	struct hfi_msg_session_property_info_pkt *pkt = packet;
429 	struct device *dev = core->dev;
430 	union hfi_get_property *hprop = &inst->hprop;
431 	unsigned int error = HFI_ERR_NONE;
432 
433 	if (!pkt->num_properties) {
434 		error = HFI_ERR_SESSION_INVALID_PARAMETER;
435 		dev_err(dev, "%s: no properties\n", __func__);
436 		goto done;
437 	}
438 
439 	switch (pkt->data[0]) {
440 	case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
441 		memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
442 		error = session_get_prop_buf_req(pkt, hprop->bufreq);
443 		break;
444 	case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
445 		memset(&hprop->profile_level, 0, sizeof(hprop->profile_level));
446 		error = session_get_prop_profile_level(pkt,
447 						       &hprop->profile_level);
448 		break;
449 	case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
450 		break;
451 	default:
452 		dev_dbg(dev, "%s: unknown property id:%x\n", __func__,
453 			pkt->data[0]);
454 		return;
455 	}
456 
457 done:
458 	inst->error = error;
459 	complete(&inst->done);
460 }
461 
462 static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst,
463 			       struct hfi_msg_session_init_done_pkt *pkt)
464 {
465 	struct device *dev = core->dev;
466 	u32 rem_bytes, num_props;
467 	u32 ptype, next_offset = 0;
468 	u32 err;
469 	u8 *data;
470 
471 	rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt) + sizeof(u32);
472 	if (!rem_bytes) {
473 		dev_err(dev, "%s: missing property info\n", __func__);
474 		return HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
475 	}
476 
477 	err = pkt->error_type;
478 	if (err)
479 		return err;
480 
481 	data = (u8 *)&pkt->data[0];
482 	num_props = pkt->num_properties;
483 
484 	while (err == HFI_ERR_NONE && num_props && rem_bytes >= sizeof(u32)) {
485 		ptype = *((u32 *)data);
486 		next_offset = sizeof(u32);
487 
488 		switch (ptype) {
489 		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: {
490 			struct hfi_codec_mask_supported *masks =
491 				(struct hfi_codec_mask_supported *)
492 				(data + next_offset);
493 
494 			next_offset += sizeof(*masks);
495 			num_props--;
496 			break;
497 		}
498 		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: {
499 			struct hfi_capabilities *caps;
500 			struct hfi_capability *cap;
501 			u32 num_caps;
502 
503 			if ((rem_bytes - next_offset) < sizeof(*cap)) {
504 				err = HFI_ERR_SESSION_INVALID_PARAMETER;
505 				break;
506 			}
507 
508 			caps = (struct hfi_capabilities *)(data + next_offset);
509 
510 			num_caps = caps->num_capabilities;
511 			cap = &caps->data[0];
512 			next_offset += sizeof(u32);
513 
514 			while (num_caps &&
515 			       (rem_bytes - next_offset) >= sizeof(u32)) {
516 				hfi_copy_cap_prop(cap, inst);
517 				cap++;
518 				next_offset += sizeof(*cap);
519 				num_caps--;
520 			}
521 			num_props--;
522 			break;
523 		}
524 		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: {
525 			struct hfi_uncompressed_format_supported *prop =
526 				(struct hfi_uncompressed_format_supported *)
527 				(data + next_offset);
528 			u32 num_fmt_entries;
529 			u8 *fmt;
530 			struct hfi_uncompressed_plane_info *inf;
531 
532 			if ((rem_bytes - next_offset) < sizeof(*prop)) {
533 				err = HFI_ERR_SESSION_INVALID_PARAMETER;
534 				break;
535 			}
536 
537 			num_fmt_entries = prop->format_entries;
538 			next_offset = sizeof(*prop) - sizeof(u32);
539 			fmt = (u8 *)&prop->format_info[0];
540 
541 			dev_dbg(dev, "uncomm format support num entries:%u\n",
542 				num_fmt_entries);
543 
544 			while (num_fmt_entries) {
545 				struct hfi_uncompressed_plane_constraints *cnts;
546 				u32 bytes_to_skip;
547 
548 				inf = (struct hfi_uncompressed_plane_info *)fmt;
549 
550 				if ((rem_bytes - next_offset) < sizeof(*inf)) {
551 					err = HFI_ERR_SESSION_INVALID_PARAMETER;
552 					break;
553 				}
554 
555 				dev_dbg(dev, "plane info: fmt:%x, planes:%x\n",
556 					inf->format, inf->num_planes);
557 
558 				cnts = &inf->plane_format[0];
559 				dev_dbg(dev, "%u %u %u %u\n",
560 					cnts->stride_multiples,
561 					cnts->max_stride,
562 					cnts->min_plane_buffer_height_multiple,
563 					cnts->buffer_alignment);
564 
565 				bytes_to_skip = sizeof(*inf) - sizeof(*cnts) +
566 						inf->num_planes * sizeof(*cnts);
567 
568 				fmt += bytes_to_skip;
569 				next_offset += bytes_to_skip;
570 				num_fmt_entries--;
571 			}
572 			num_props--;
573 			break;
574 		}
575 		case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: {
576 			struct hfi_properties_supported *prop =
577 				(struct hfi_properties_supported *)
578 				(data + next_offset);
579 
580 			next_offset += sizeof(*prop) - sizeof(u32)
581 					+ prop->num_properties * sizeof(u32);
582 			num_props--;
583 			break;
584 		}
585 		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: {
586 			struct hfi_profile_level_supported *prop =
587 				(struct hfi_profile_level_supported *)
588 				(data + next_offset);
589 			struct hfi_profile_level *pl;
590 			unsigned int prop_count = 0;
591 			unsigned int count = 0;
592 			u8 *ptr;
593 
594 			ptr = (u8 *)&prop->profile_level[0];
595 			prop_count = prop->profile_count;
596 
597 			if (prop_count > HFI_MAX_PROFILE_COUNT)
598 				prop_count = HFI_MAX_PROFILE_COUNT;
599 
600 			while (prop_count) {
601 				ptr++;
602 				pl = (struct hfi_profile_level *)ptr;
603 
604 				inst->pl[count].profile = pl->profile;
605 				inst->pl[count].level = pl->level;
606 				prop_count--;
607 				count++;
608 				ptr += sizeof(*pl) / sizeof(u32);
609 			}
610 
611 			inst->pl_count = count;
612 			next_offset += sizeof(*prop) - sizeof(*pl) +
613 				       prop->profile_count * sizeof(*pl);
614 
615 			num_props--;
616 			break;
617 		}
618 		case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: {
619 			next_offset +=
620 				sizeof(struct hfi_interlace_format_supported);
621 			num_props--;
622 			break;
623 		}
624 		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: {
625 			struct hfi_nal_stream_format *nal =
626 				(struct hfi_nal_stream_format *)
627 				(data + next_offset);
628 			dev_dbg(dev, "NAL format: %x\n", nal->format);
629 			next_offset += sizeof(*nal);
630 			num_props--;
631 			break;
632 		}
633 		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: {
634 			next_offset += sizeof(u32);
635 			num_props--;
636 			break;
637 		}
638 		case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: {
639 			u32 *max_seq_sz = (u32 *)(data + next_offset);
640 
641 			dev_dbg(dev, "max seq header sz: %x\n", *max_seq_sz);
642 			next_offset += sizeof(u32);
643 			num_props--;
644 			break;
645 		}
646 		case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: {
647 			next_offset += sizeof(struct hfi_intra_refresh);
648 			num_props--;
649 			break;
650 		}
651 		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: {
652 			struct hfi_buffer_alloc_mode_supported *prop =
653 				(struct hfi_buffer_alloc_mode_supported *)
654 				(data + next_offset);
655 			unsigned int i;
656 
657 			for (i = 0; i < prop->num_entries; i++) {
658 				if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
659 				    prop->buffer_type == HFI_BUFFER_OUTPUT2) {
660 					switch (prop->data[i]) {
661 					case HFI_BUFFER_MODE_STATIC:
662 						inst->cap_bufs_mode_static = 1;
663 						break;
664 					case HFI_BUFFER_MODE_DYNAMIC:
665 						inst->cap_bufs_mode_dynamic = 1;
666 						break;
667 					default:
668 						break;
669 					}
670 				}
671 			}
672 			next_offset += sizeof(*prop) -
673 				sizeof(u32) + prop->num_entries * sizeof(u32);
674 			num_props--;
675 			break;
676 		}
677 		default:
678 			dev_dbg(dev, "%s: default case %#x\n", __func__, ptype);
679 			break;
680 		}
681 
682 		rem_bytes -= next_offset;
683 		data += next_offset;
684 	}
685 
686 	return err;
687 }
688 
689 static void hfi_session_init_done(struct venus_core *core,
690 				  struct venus_inst *inst, void *packet)
691 {
692 	struct hfi_msg_session_init_done_pkt *pkt = packet;
693 	unsigned int error;
694 
695 	error = pkt->error_type;
696 	if (error != HFI_ERR_NONE)
697 		goto done;
698 
699 	if (core->res->hfi_version != HFI_VERSION_1XX)
700 		goto done;
701 
702 	error = init_done_read_prop(core, inst, pkt);
703 
704 done:
705 	inst->error = error;
706 	complete(&inst->done);
707 }
708 
709 static void hfi_session_load_res_done(struct venus_core *core,
710 				      struct venus_inst *inst, void *packet)
711 {
712 	struct hfi_msg_session_load_resources_done_pkt *pkt = packet;
713 
714 	inst->error = pkt->error_type;
715 	complete(&inst->done);
716 }
717 
718 static void hfi_session_flush_done(struct venus_core *core,
719 				   struct venus_inst *inst, void *packet)
720 {
721 	struct hfi_msg_session_flush_done_pkt *pkt = packet;
722 
723 	inst->error = pkt->error_type;
724 	complete(&inst->done);
725 }
726 
727 static void hfi_session_etb_done(struct venus_core *core,
728 				 struct venus_inst *inst, void *packet)
729 {
730 	struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
731 
732 	inst->error = pkt->error_type;
733 	inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag,
734 			    pkt->filled_len, pkt->offset, 0, 0, 0);
735 }
736 
737 static void hfi_session_ftb_done(struct venus_core *core,
738 				 struct venus_inst *inst, void *packet)
739 {
740 	u32 session_type = inst->session_type;
741 	u64 timestamp_us = 0;
742 	u32 timestamp_hi = 0, timestamp_lo = 0;
743 	unsigned int error;
744 	u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0;
745 	u32 pic_type = 0, buffer_type = 0, output_tag = -1;
746 
747 	if (session_type == VIDC_SESSION_TYPE_ENC) {
748 		struct hfi_msg_session_fbd_compressed_pkt *pkt = packet;
749 
750 		timestamp_hi = pkt->time_stamp_hi;
751 		timestamp_lo = pkt->time_stamp_lo;
752 		hfi_flags = pkt->flags;
753 		offset = pkt->offset;
754 		filled_len = pkt->filled_len;
755 		pic_type = pkt->picture_type;
756 		output_tag = pkt->output_tag;
757 		buffer_type = HFI_BUFFER_OUTPUT;
758 
759 		error = pkt->error_type;
760 	} else if (session_type == VIDC_SESSION_TYPE_DEC) {
761 		struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt =
762 			packet;
763 
764 		timestamp_hi = pkt->time_stamp_hi;
765 		timestamp_lo = pkt->time_stamp_lo;
766 		hfi_flags = pkt->flags;
767 		offset = pkt->offset;
768 		filled_len = pkt->filled_len;
769 		pic_type = pkt->picture_type;
770 		output_tag = pkt->output_tag;
771 
772 		if (pkt->stream_id == 0)
773 			buffer_type = HFI_BUFFER_OUTPUT;
774 		else if (pkt->stream_id == 1)
775 			buffer_type = HFI_BUFFER_OUTPUT2;
776 
777 		error = pkt->error_type;
778 	} else {
779 		error = HFI_ERR_SESSION_INVALID_PARAMETER;
780 	}
781 
782 	if (buffer_type != HFI_BUFFER_OUTPUT)
783 		goto done;
784 
785 	if (hfi_flags & HFI_BUFFERFLAG_EOS)
786 		flags |= V4L2_BUF_FLAG_LAST;
787 
788 	switch (pic_type) {
789 	case HFI_PICTURE_IDR:
790 	case HFI_PICTURE_I:
791 		flags |= V4L2_BUF_FLAG_KEYFRAME;
792 		break;
793 	case HFI_PICTURE_P:
794 		flags |= V4L2_BUF_FLAG_PFRAME;
795 		break;
796 	case HFI_PICTURE_B:
797 		flags |= V4L2_BUF_FLAG_BFRAME;
798 		break;
799 	case HFI_FRAME_NOTCODED:
800 	case HFI_UNUSED_PICT:
801 	case HFI_FRAME_YUV:
802 	default:
803 		break;
804 	}
805 
806 	if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) {
807 		timestamp_us = timestamp_hi;
808 		timestamp_us = (timestamp_us << 32) | timestamp_lo;
809 	}
810 
811 done:
812 	inst->error = error;
813 	inst->ops->buf_done(inst, buffer_type, output_tag, filled_len,
814 			    offset, flags, hfi_flags, timestamp_us);
815 }
816 
817 static void hfi_session_start_done(struct venus_core *core,
818 				   struct venus_inst *inst, void *packet)
819 {
820 	struct hfi_msg_session_start_done_pkt *pkt = packet;
821 
822 	inst->error = pkt->error_type;
823 	complete(&inst->done);
824 }
825 
826 static void hfi_session_stop_done(struct venus_core *core,
827 				  struct venus_inst *inst, void *packet)
828 {
829 	struct hfi_msg_session_stop_done_pkt *pkt = packet;
830 
831 	inst->error = pkt->error_type;
832 	complete(&inst->done);
833 }
834 
835 static void hfi_session_rel_res_done(struct venus_core *core,
836 				     struct venus_inst *inst, void *packet)
837 {
838 	struct hfi_msg_session_release_resources_done_pkt *pkt = packet;
839 
840 	inst->error = pkt->error_type;
841 	complete(&inst->done);
842 }
843 
844 static void hfi_session_rel_buf_done(struct venus_core *core,
845 				     struct venus_inst *inst, void *packet)
846 {
847 	struct hfi_msg_session_release_buffers_done_pkt *pkt = packet;
848 
849 	inst->error = pkt->error_type;
850 	complete(&inst->done);
851 }
852 
853 static void hfi_session_end_done(struct venus_core *core,
854 				 struct venus_inst *inst, void *packet)
855 {
856 	struct hfi_msg_session_end_done_pkt *pkt = packet;
857 
858 	inst->error = pkt->error_type;
859 	complete(&inst->done);
860 }
861 
862 static void hfi_session_abort_done(struct venus_core *core,
863 				   struct venus_inst *inst, void *packet)
864 {
865 	struct hfi_msg_sys_session_abort_done_pkt *pkt = packet;
866 
867 	inst->error = pkt->error_type;
868 	complete(&inst->done);
869 }
870 
871 static void hfi_session_get_seq_hdr_done(struct venus_core *core,
872 					 struct venus_inst *inst, void *packet)
873 {
874 	struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet;
875 
876 	inst->error = pkt->error_type;
877 	complete(&inst->done);
878 }
879 
880 struct hfi_done_handler {
881 	u32 pkt;
882 	u32 pkt_sz;
883 	u32 pkt_sz2;
884 	void (*done)(struct venus_core *, struct venus_inst *, void *);
885 	bool is_sys_pkt;
886 };
887 
888 static const struct hfi_done_handler handlers[] = {
889 	{.pkt = HFI_MSG_EVENT_NOTIFY,
890 	 .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt),
891 	 .done = hfi_event_notify,
892 	},
893 	{.pkt = HFI_MSG_SYS_INIT,
894 	 .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt),
895 	 .done = hfi_sys_init_done,
896 	 .is_sys_pkt = true,
897 	},
898 	{.pkt = HFI_MSG_SYS_PROPERTY_INFO,
899 	 .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt),
900 	 .done = hfi_sys_property_info,
901 	 .is_sys_pkt = true,
902 	},
903 	{.pkt = HFI_MSG_SYS_RELEASE_RESOURCE,
904 	 .pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt),
905 	 .done = hfi_sys_rel_resource_done,
906 	 .is_sys_pkt = true,
907 	},
908 	{.pkt = HFI_MSG_SYS_PING_ACK,
909 	 .pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt),
910 	 .done = hfi_sys_ping_done,
911 	 .is_sys_pkt = true,
912 	},
913 	{.pkt = HFI_MSG_SYS_IDLE,
914 	 .pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt),
915 	 .done = hfi_sys_idle_done,
916 	 .is_sys_pkt = true,
917 	},
918 	{.pkt = HFI_MSG_SYS_PC_PREP,
919 	 .pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt),
920 	 .done = hfi_sys_pc_prepare_done,
921 	 .is_sys_pkt = true,
922 	},
923 	{.pkt = HFI_MSG_SYS_SESSION_INIT,
924 	 .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt),
925 	 .done = hfi_session_init_done,
926 	},
927 	{.pkt = HFI_MSG_SYS_SESSION_END,
928 	 .pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt),
929 	 .done = hfi_session_end_done,
930 	},
931 	{.pkt = HFI_MSG_SESSION_LOAD_RESOURCES,
932 	 .pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt),
933 	 .done = hfi_session_load_res_done,
934 	},
935 	{.pkt = HFI_MSG_SESSION_START,
936 	 .pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt),
937 	 .done = hfi_session_start_done,
938 	},
939 	{.pkt = HFI_MSG_SESSION_STOP,
940 	 .pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt),
941 	 .done = hfi_session_stop_done,
942 	},
943 	{.pkt = HFI_MSG_SYS_SESSION_ABORT,
944 	 .pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt),
945 	 .done = hfi_session_abort_done,
946 	},
947 	{.pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
948 	 .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
949 	 .done = hfi_session_etb_done,
950 	},
951 	{.pkt = HFI_MSG_SESSION_FILL_BUFFER,
952 	 .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt),
953 	 .pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt),
954 	 .done = hfi_session_ftb_done,
955 	},
956 	{.pkt = HFI_MSG_SESSION_FLUSH,
957 	 .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
958 	 .done = hfi_session_flush_done,
959 	},
960 	{.pkt = HFI_MSG_SESSION_PROPERTY_INFO,
961 	 .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt),
962 	 .done = hfi_session_prop_info,
963 	},
964 	{.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
965 	 .pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt),
966 	 .done = hfi_session_rel_res_done,
967 	},
968 	{.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER,
969 	 .pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt),
970 	 .done = hfi_session_get_seq_hdr_done,
971 	},
972 	{.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
973 	 .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
974 	 .done = hfi_session_rel_buf_done,
975 	},
976 };
977 
978 void hfi_process_watchdog_timeout(struct venus_core *core)
979 {
980 	event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL);
981 }
982 
983 static struct venus_inst *to_instance(struct venus_core *core, u32 session_id)
984 {
985 	struct venus_inst *inst;
986 
987 	mutex_lock(&core->lock);
988 	list_for_each_entry(inst, &core->instances, list)
989 		if (hash32_ptr(inst) == session_id) {
990 			mutex_unlock(&core->lock);
991 			return inst;
992 		}
993 	mutex_unlock(&core->lock);
994 
995 	return NULL;
996 }
997 
998 u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr)
999 {
1000 	const struct hfi_done_handler *handler;
1001 	struct device *dev = core->dev;
1002 	struct venus_inst *inst;
1003 	bool found = false;
1004 	unsigned int i;
1005 
1006 	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
1007 		handler = &handlers[i];
1008 		if (handler->pkt != hdr->pkt_type)
1009 			continue;
1010 		found = true;
1011 		break;
1012 	}
1013 
1014 	if (!found)
1015 		return hdr->pkt_type;
1016 
1017 	if (hdr->size && hdr->size < handler->pkt_sz &&
1018 	    hdr->size < handler->pkt_sz2) {
1019 		dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n",
1020 			hdr->size, handler->pkt_sz, hdr->pkt_type);
1021 
1022 		return hdr->pkt_type;
1023 	}
1024 
1025 	if (handler->is_sys_pkt) {
1026 		inst = NULL;
1027 	} else {
1028 		struct hfi_session_pkt *pkt;
1029 
1030 		pkt = (struct hfi_session_pkt *)hdr;
1031 		inst = to_instance(core, pkt->shdr.session_id);
1032 
1033 		if (!inst)
1034 			dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n",
1035 				 pkt->shdr.session_id,
1036 				 handler ? handler->pkt : 0);
1037 
1038 		/*
1039 		 * Event of type HFI_EVENT_SYS_ERROR will not have any session
1040 		 * associated with it
1041 		 */
1042 		if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) {
1043 			dev_err(dev, "got invalid session id:%x\n",
1044 				pkt->shdr.session_id);
1045 			goto invalid_session;
1046 		}
1047 	}
1048 
1049 	handler->done(core, inst, hdr);
1050 
1051 invalid_session:
1052 	return hdr->pkt_type;
1053 }
1054