]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/media/platform/qcom/venus/hfi_msgs.c
scsi: qedf: Fix a potential NULL pointer dereference
[mirror_ubuntu-artful-kernel.git] / drivers / media / platform / qcom / venus / hfi_msgs.c
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 rem_bytes -= read_bytes;
244 data += read_bytes;
245 num_properties--;
246 }
247 }
248
249 err_no_prop:
250 core->error = error;
251 complete(&core->done);
252 }
253
254 static void
255 sys_get_prop_image_version(struct device *dev,
256 struct hfi_msg_sys_property_info_pkt *pkt)
257 {
258 int req_bytes;
259
260 req_bytes = pkt->hdr.size - sizeof(*pkt);
261
262 if (req_bytes < 128 || !pkt->data[1] || pkt->num_properties > 1)
263 /* bad packet */
264 return;
265
266 dev_dbg(dev, "F/W version: %s\n", (u8 *)&pkt->data[1]);
267 }
268
269 static void hfi_sys_property_info(struct venus_core *core,
270 struct venus_inst *inst, void *packet)
271 {
272 struct hfi_msg_sys_property_info_pkt *pkt = packet;
273 struct device *dev = core->dev;
274
275 if (!pkt->num_properties) {
276 dev_dbg(dev, "%s: no properties\n", __func__);
277 return;
278 }
279
280 switch (pkt->data[0]) {
281 case HFI_PROPERTY_SYS_IMAGE_VERSION:
282 sys_get_prop_image_version(dev, pkt);
283 break;
284 default:
285 dev_dbg(dev, "%s: unknown property data\n", __func__);
286 break;
287 }
288 }
289
290 static void hfi_sys_rel_resource_done(struct venus_core *core,
291 struct venus_inst *inst,
292 void *packet)
293 {
294 struct hfi_msg_sys_release_resource_done_pkt *pkt = packet;
295
296 core->error = pkt->error_type;
297 complete(&core->done);
298 }
299
300 static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst,
301 void *packet)
302 {
303 struct hfi_msg_sys_ping_ack_pkt *pkt = packet;
304
305 core->error = HFI_ERR_NONE;
306
307 if (pkt->client_data != 0xbeef)
308 core->error = HFI_ERR_SYS_FATAL;
309
310 complete(&core->done);
311 }
312
313 static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst,
314 void *packet)
315 {
316 dev_dbg(core->dev, "sys idle\n");
317 }
318
319 static void hfi_sys_pc_prepare_done(struct venus_core *core,
320 struct venus_inst *inst, void *packet)
321 {
322 struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet;
323
324 dev_dbg(core->dev, "pc prepare done (error %x)\n", pkt->error_type);
325 }
326
327 static void
328 hfi_copy_cap_prop(struct hfi_capability *in, struct venus_inst *inst)
329 {
330 if (!in || !inst)
331 return;
332
333 switch (in->capability_type) {
334 case HFI_CAPABILITY_FRAME_WIDTH:
335 inst->cap_width = *in;
336 break;
337 case HFI_CAPABILITY_FRAME_HEIGHT:
338 inst->cap_height = *in;
339 break;
340 case HFI_CAPABILITY_MBS_PER_FRAME:
341 inst->cap_mbs_per_frame = *in;
342 break;
343 case HFI_CAPABILITY_MBS_PER_SECOND:
344 inst->cap_mbs_per_sec = *in;
345 break;
346 case HFI_CAPABILITY_FRAMERATE:
347 inst->cap_framerate = *in;
348 break;
349 case HFI_CAPABILITY_SCALE_X:
350 inst->cap_scale_x = *in;
351 break;
352 case HFI_CAPABILITY_SCALE_Y:
353 inst->cap_scale_y = *in;
354 break;
355 case HFI_CAPABILITY_BITRATE:
356 inst->cap_bitrate = *in;
357 break;
358 case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
359 inst->cap_hier_p = *in;
360 break;
361 case HFI_CAPABILITY_ENC_LTR_COUNT:
362 inst->cap_ltr_count = *in;
363 break;
364 case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
365 inst->cap_secure_output2_threshold = *in;
366 break;
367 default:
368 break;
369 }
370 }
371
372 static unsigned int
373 session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
374 struct hfi_profile_level *profile_level)
375 {
376 struct hfi_profile_level *hfi;
377 u32 req_bytes;
378
379 req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
380
381 if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level))
382 /* bad packet */
383 return HFI_ERR_SESSION_INVALID_PARAMETER;
384
385 hfi = (struct hfi_profile_level *)&pkt->data[1];
386 profile_level->profile = hfi->profile;
387 profile_level->level = hfi->level;
388
389 return HFI_ERR_NONE;
390 }
391
392 static unsigned int
393 session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
394 struct hfi_buffer_requirements *bufreq)
395 {
396 struct hfi_buffer_requirements *buf_req;
397 u32 req_bytes;
398 unsigned int idx = 0;
399
400 req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
401
402 if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1])
403 /* bad packet */
404 return HFI_ERR_SESSION_INVALID_PARAMETER;
405
406 buf_req = (struct hfi_buffer_requirements *)&pkt->data[1];
407 if (!buf_req)
408 return HFI_ERR_SESSION_INVALID_PARAMETER;
409
410 while (req_bytes) {
411 memcpy(&bufreq[idx], buf_req, sizeof(*bufreq));
412 idx++;
413
414 if (idx > HFI_BUFFER_TYPE_MAX)
415 return HFI_ERR_SESSION_INVALID_PARAMETER;
416
417 req_bytes -= sizeof(struct hfi_buffer_requirements);
418 buf_req++;
419 }
420
421 return HFI_ERR_NONE;
422 }
423
424 static void hfi_session_prop_info(struct venus_core *core,
425 struct venus_inst *inst, void *packet)
426 {
427 struct hfi_msg_session_property_info_pkt *pkt = packet;
428 struct device *dev = core->dev;
429 union hfi_get_property *hprop = &inst->hprop;
430 unsigned int error = HFI_ERR_NONE;
431
432 if (!pkt->num_properties) {
433 error = HFI_ERR_SESSION_INVALID_PARAMETER;
434 dev_err(dev, "%s: no properties\n", __func__);
435 goto done;
436 }
437
438 switch (pkt->data[0]) {
439 case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
440 memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
441 error = session_get_prop_buf_req(pkt, hprop->bufreq);
442 break;
443 case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
444 memset(&hprop->profile_level, 0, sizeof(hprop->profile_level));
445 error = session_get_prop_profile_level(pkt,
446 &hprop->profile_level);
447 break;
448 case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
449 break;
450 default:
451 dev_dbg(dev, "%s: unknown property id:%x\n", __func__,
452 pkt->data[0]);
453 return;
454 }
455
456 done:
457 inst->error = error;
458 complete(&inst->done);
459 }
460
461 static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst,
462 struct hfi_msg_session_init_done_pkt *pkt)
463 {
464 struct device *dev = core->dev;
465 u32 rem_bytes, num_props;
466 u32 ptype, next_offset = 0;
467 u32 err;
468 u8 *data;
469
470 rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt) + sizeof(u32);
471 if (!rem_bytes) {
472 dev_err(dev, "%s: missing property info\n", __func__);
473 return HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
474 }
475
476 err = pkt->error_type;
477 if (err)
478 return err;
479
480 data = (u8 *)&pkt->data[0];
481 num_props = pkt->num_properties;
482
483 while (err == HFI_ERR_NONE && num_props && rem_bytes >= sizeof(u32)) {
484 ptype = *((u32 *)data);
485 next_offset = sizeof(u32);
486
487 switch (ptype) {
488 case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: {
489 struct hfi_codec_mask_supported *masks =
490 (struct hfi_codec_mask_supported *)
491 (data + next_offset);
492
493 next_offset += sizeof(*masks);
494 num_props--;
495 break;
496 }
497 case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: {
498 struct hfi_capabilities *caps;
499 struct hfi_capability *cap;
500 u32 num_caps;
501
502 if ((rem_bytes - next_offset) < sizeof(*cap)) {
503 err = HFI_ERR_SESSION_INVALID_PARAMETER;
504 break;
505 }
506
507 caps = (struct hfi_capabilities *)(data + next_offset);
508
509 num_caps = caps->num_capabilities;
510 cap = &caps->data[0];
511 next_offset += sizeof(u32);
512
513 while (num_caps &&
514 (rem_bytes - next_offset) >= sizeof(u32)) {
515 hfi_copy_cap_prop(cap, inst);
516 cap++;
517 next_offset += sizeof(*cap);
518 num_caps--;
519 }
520 num_props--;
521 break;
522 }
523 case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: {
524 struct hfi_uncompressed_format_supported *prop =
525 (struct hfi_uncompressed_format_supported *)
526 (data + next_offset);
527 u32 num_fmt_entries;
528 u8 *fmt;
529 struct hfi_uncompressed_plane_info *inf;
530
531 if ((rem_bytes - next_offset) < sizeof(*prop)) {
532 err = HFI_ERR_SESSION_INVALID_PARAMETER;
533 break;
534 }
535
536 num_fmt_entries = prop->format_entries;
537 next_offset = sizeof(*prop) - sizeof(u32);
538 fmt = (u8 *)&prop->format_info[0];
539
540 dev_dbg(dev, "uncomm format support num entries:%u\n",
541 num_fmt_entries);
542
543 while (num_fmt_entries) {
544 struct hfi_uncompressed_plane_constraints *cnts;
545 u32 bytes_to_skip;
546
547 inf = (struct hfi_uncompressed_plane_info *)fmt;
548
549 if ((rem_bytes - next_offset) < sizeof(*inf)) {
550 err = HFI_ERR_SESSION_INVALID_PARAMETER;
551 break;
552 }
553
554 dev_dbg(dev, "plane info: fmt:%x, planes:%x\n",
555 inf->format, inf->num_planes);
556
557 cnts = &inf->plane_format[0];
558 dev_dbg(dev, "%u %u %u %u\n",
559 cnts->stride_multiples,
560 cnts->max_stride,
561 cnts->min_plane_buffer_height_multiple,
562 cnts->buffer_alignment);
563
564 bytes_to_skip = sizeof(*inf) - sizeof(*cnts) +
565 inf->num_planes * sizeof(*cnts);
566
567 fmt += bytes_to_skip;
568 next_offset += bytes_to_skip;
569 num_fmt_entries--;
570 }
571 num_props--;
572 break;
573 }
574 case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: {
575 struct hfi_properties_supported *prop =
576 (struct hfi_properties_supported *)
577 (data + next_offset);
578
579 next_offset += sizeof(*prop) - sizeof(u32)
580 + prop->num_properties * sizeof(u32);
581 num_props--;
582 break;
583 }
584 case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: {
585 struct hfi_profile_level_supported *prop =
586 (struct hfi_profile_level_supported *)
587 (data + next_offset);
588 struct hfi_profile_level *pl;
589 unsigned int prop_count = 0;
590 unsigned int count = 0;
591 u8 *ptr;
592
593 ptr = (u8 *)&prop->profile_level[0];
594 prop_count = prop->profile_count;
595
596 if (prop_count > HFI_MAX_PROFILE_COUNT)
597 prop_count = HFI_MAX_PROFILE_COUNT;
598
599 while (prop_count) {
600 ptr++;
601 pl = (struct hfi_profile_level *)ptr;
602
603 inst->pl[count].profile = pl->profile;
604 inst->pl[count].level = pl->level;
605 prop_count--;
606 count++;
607 ptr += sizeof(*pl) / sizeof(u32);
608 }
609
610 inst->pl_count = count;
611 next_offset += sizeof(*prop) - sizeof(*pl) +
612 prop->profile_count * sizeof(*pl);
613
614 num_props--;
615 break;
616 }
617 case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: {
618 next_offset +=
619 sizeof(struct hfi_interlace_format_supported);
620 num_props--;
621 break;
622 }
623 case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: {
624 struct hfi_nal_stream_format *nal =
625 (struct hfi_nal_stream_format *)
626 (data + next_offset);
627 dev_dbg(dev, "NAL format: %x\n", nal->format);
628 next_offset += sizeof(*nal);
629 num_props--;
630 break;
631 }
632 case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: {
633 next_offset += sizeof(u32);
634 num_props--;
635 break;
636 }
637 case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: {
638 u32 *max_seq_sz = (u32 *)(data + next_offset);
639
640 dev_dbg(dev, "max seq header sz: %x\n", *max_seq_sz);
641 next_offset += sizeof(u32);
642 num_props--;
643 break;
644 }
645 case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: {
646 next_offset += sizeof(struct hfi_intra_refresh);
647 num_props--;
648 break;
649 }
650 case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: {
651 struct hfi_buffer_alloc_mode_supported *prop =
652 (struct hfi_buffer_alloc_mode_supported *)
653 (data + next_offset);
654 unsigned int i;
655
656 for (i = 0; i < prop->num_entries; i++) {
657 if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
658 prop->buffer_type == HFI_BUFFER_OUTPUT2) {
659 switch (prop->data[i]) {
660 case HFI_BUFFER_MODE_STATIC:
661 inst->cap_bufs_mode_static = 1;
662 break;
663 case HFI_BUFFER_MODE_DYNAMIC:
664 inst->cap_bufs_mode_dynamic = 1;
665 break;
666 default:
667 break;
668 }
669 }
670 }
671 next_offset += sizeof(*prop) -
672 sizeof(u32) + prop->num_entries * sizeof(u32);
673 num_props--;
674 break;
675 }
676 default:
677 dev_dbg(dev, "%s: default case %#x\n", __func__, ptype);
678 break;
679 }
680
681 rem_bytes -= next_offset;
682 data += next_offset;
683 }
684
685 return err;
686 }
687
688 static void hfi_session_init_done(struct venus_core *core,
689 struct venus_inst *inst, void *packet)
690 {
691 struct hfi_msg_session_init_done_pkt *pkt = packet;
692 unsigned int error;
693
694 error = pkt->error_type;
695 if (error != HFI_ERR_NONE)
696 goto done;
697
698 if (core->res->hfi_version != HFI_VERSION_1XX)
699 goto done;
700
701 error = init_done_read_prop(core, inst, pkt);
702
703 done:
704 inst->error = error;
705 complete(&inst->done);
706 }
707
708 static void hfi_session_load_res_done(struct venus_core *core,
709 struct venus_inst *inst, void *packet)
710 {
711 struct hfi_msg_session_load_resources_done_pkt *pkt = packet;
712
713 inst->error = pkt->error_type;
714 complete(&inst->done);
715 }
716
717 static void hfi_session_flush_done(struct venus_core *core,
718 struct venus_inst *inst, void *packet)
719 {
720 struct hfi_msg_session_flush_done_pkt *pkt = packet;
721
722 inst->error = pkt->error_type;
723 complete(&inst->done);
724 }
725
726 static void hfi_session_etb_done(struct venus_core *core,
727 struct venus_inst *inst, void *packet)
728 {
729 struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
730
731 inst->error = pkt->error_type;
732 inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag,
733 pkt->filled_len, pkt->offset, 0, 0, 0);
734 }
735
736 static void hfi_session_ftb_done(struct venus_core *core,
737 struct venus_inst *inst, void *packet)
738 {
739 u32 session_type = inst->session_type;
740 u64 timestamp_us = 0;
741 u32 timestamp_hi = 0, timestamp_lo = 0;
742 unsigned int error;
743 u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0;
744 u32 pic_type = 0, buffer_type = 0, output_tag = -1;
745
746 if (session_type == VIDC_SESSION_TYPE_ENC) {
747 struct hfi_msg_session_fbd_compressed_pkt *pkt = packet;
748
749 timestamp_hi = pkt->time_stamp_hi;
750 timestamp_lo = pkt->time_stamp_lo;
751 hfi_flags = pkt->flags;
752 offset = pkt->offset;
753 filled_len = pkt->filled_len;
754 pic_type = pkt->picture_type;
755 output_tag = pkt->output_tag;
756 buffer_type = HFI_BUFFER_OUTPUT;
757
758 error = pkt->error_type;
759 } else if (session_type == VIDC_SESSION_TYPE_DEC) {
760 struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt =
761 packet;
762
763 timestamp_hi = pkt->time_stamp_hi;
764 timestamp_lo = pkt->time_stamp_lo;
765 hfi_flags = pkt->flags;
766 offset = pkt->offset;
767 filled_len = pkt->filled_len;
768 pic_type = pkt->picture_type;
769 output_tag = pkt->output_tag;
770
771 if (pkt->stream_id == 0)
772 buffer_type = HFI_BUFFER_OUTPUT;
773 else if (pkt->stream_id == 1)
774 buffer_type = HFI_BUFFER_OUTPUT2;
775
776 error = pkt->error_type;
777 } else {
778 error = HFI_ERR_SESSION_INVALID_PARAMETER;
779 }
780
781 if (buffer_type != HFI_BUFFER_OUTPUT)
782 goto done;
783
784 if (hfi_flags & HFI_BUFFERFLAG_EOS)
785 flags |= V4L2_BUF_FLAG_LAST;
786
787 switch (pic_type) {
788 case HFI_PICTURE_IDR:
789 case HFI_PICTURE_I:
790 flags |= V4L2_BUF_FLAG_KEYFRAME;
791 break;
792 case HFI_PICTURE_P:
793 flags |= V4L2_BUF_FLAG_PFRAME;
794 break;
795 case HFI_PICTURE_B:
796 flags |= V4L2_BUF_FLAG_BFRAME;
797 break;
798 case HFI_FRAME_NOTCODED:
799 case HFI_UNUSED_PICT:
800 case HFI_FRAME_YUV:
801 default:
802 break;
803 }
804
805 if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) {
806 timestamp_us = timestamp_hi;
807 timestamp_us = (timestamp_us << 32) | timestamp_lo;
808 }
809
810 done:
811 inst->error = error;
812 inst->ops->buf_done(inst, buffer_type, output_tag, filled_len,
813 offset, flags, hfi_flags, timestamp_us);
814 }
815
816 static void hfi_session_start_done(struct venus_core *core,
817 struct venus_inst *inst, void *packet)
818 {
819 struct hfi_msg_session_start_done_pkt *pkt = packet;
820
821 inst->error = pkt->error_type;
822 complete(&inst->done);
823 }
824
825 static void hfi_session_stop_done(struct venus_core *core,
826 struct venus_inst *inst, void *packet)
827 {
828 struct hfi_msg_session_stop_done_pkt *pkt = packet;
829
830 inst->error = pkt->error_type;
831 complete(&inst->done);
832 }
833
834 static void hfi_session_rel_res_done(struct venus_core *core,
835 struct venus_inst *inst, void *packet)
836 {
837 struct hfi_msg_session_release_resources_done_pkt *pkt = packet;
838
839 inst->error = pkt->error_type;
840 complete(&inst->done);
841 }
842
843 static void hfi_session_rel_buf_done(struct venus_core *core,
844 struct venus_inst *inst, void *packet)
845 {
846 struct hfi_msg_session_release_buffers_done_pkt *pkt = packet;
847
848 inst->error = pkt->error_type;
849 complete(&inst->done);
850 }
851
852 static void hfi_session_end_done(struct venus_core *core,
853 struct venus_inst *inst, void *packet)
854 {
855 struct hfi_msg_session_end_done_pkt *pkt = packet;
856
857 inst->error = pkt->error_type;
858 complete(&inst->done);
859 }
860
861 static void hfi_session_abort_done(struct venus_core *core,
862 struct venus_inst *inst, void *packet)
863 {
864 struct hfi_msg_sys_session_abort_done_pkt *pkt = packet;
865
866 inst->error = pkt->error_type;
867 complete(&inst->done);
868 }
869
870 static void hfi_session_get_seq_hdr_done(struct venus_core *core,
871 struct venus_inst *inst, void *packet)
872 {
873 struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet;
874
875 inst->error = pkt->error_type;
876 complete(&inst->done);
877 }
878
879 struct hfi_done_handler {
880 u32 pkt;
881 u32 pkt_sz;
882 u32 pkt_sz2;
883 void (*done)(struct venus_core *, struct venus_inst *, void *);
884 bool is_sys_pkt;
885 };
886
887 static const struct hfi_done_handler handlers[] = {
888 {.pkt = HFI_MSG_EVENT_NOTIFY,
889 .pkt_sz = sizeof(struct hfi_msg_event_notify_pkt),
890 .done = hfi_event_notify,
891 },
892 {.pkt = HFI_MSG_SYS_INIT,
893 .pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt),
894 .done = hfi_sys_init_done,
895 .is_sys_pkt = true,
896 },
897 {.pkt = HFI_MSG_SYS_PROPERTY_INFO,
898 .pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt),
899 .done = hfi_sys_property_info,
900 .is_sys_pkt = true,
901 },
902 {.pkt = HFI_MSG_SYS_RELEASE_RESOURCE,
903 .pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt),
904 .done = hfi_sys_rel_resource_done,
905 .is_sys_pkt = true,
906 },
907 {.pkt = HFI_MSG_SYS_PING_ACK,
908 .pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt),
909 .done = hfi_sys_ping_done,
910 .is_sys_pkt = true,
911 },
912 {.pkt = HFI_MSG_SYS_IDLE,
913 .pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt),
914 .done = hfi_sys_idle_done,
915 .is_sys_pkt = true,
916 },
917 {.pkt = HFI_MSG_SYS_PC_PREP,
918 .pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt),
919 .done = hfi_sys_pc_prepare_done,
920 .is_sys_pkt = true,
921 },
922 {.pkt = HFI_MSG_SYS_SESSION_INIT,
923 .pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt),
924 .done = hfi_session_init_done,
925 },
926 {.pkt = HFI_MSG_SYS_SESSION_END,
927 .pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt),
928 .done = hfi_session_end_done,
929 },
930 {.pkt = HFI_MSG_SESSION_LOAD_RESOURCES,
931 .pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt),
932 .done = hfi_session_load_res_done,
933 },
934 {.pkt = HFI_MSG_SESSION_START,
935 .pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt),
936 .done = hfi_session_start_done,
937 },
938 {.pkt = HFI_MSG_SESSION_STOP,
939 .pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt),
940 .done = hfi_session_stop_done,
941 },
942 {.pkt = HFI_MSG_SYS_SESSION_ABORT,
943 .pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt),
944 .done = hfi_session_abort_done,
945 },
946 {.pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
947 .pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
948 .done = hfi_session_etb_done,
949 },
950 {.pkt = HFI_MSG_SESSION_FILL_BUFFER,
951 .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt),
952 .pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt),
953 .done = hfi_session_ftb_done,
954 },
955 {.pkt = HFI_MSG_SESSION_FLUSH,
956 .pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
957 .done = hfi_session_flush_done,
958 },
959 {.pkt = HFI_MSG_SESSION_PROPERTY_INFO,
960 .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt),
961 .done = hfi_session_prop_info,
962 },
963 {.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
964 .pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt),
965 .done = hfi_session_rel_res_done,
966 },
967 {.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER,
968 .pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt),
969 .done = hfi_session_get_seq_hdr_done,
970 },
971 {.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
972 .pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
973 .done = hfi_session_rel_buf_done,
974 },
975 };
976
977 void hfi_process_watchdog_timeout(struct venus_core *core)
978 {
979 event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL);
980 }
981
982 static struct venus_inst *to_instance(struct venus_core *core, u32 session_id)
983 {
984 struct venus_inst *inst;
985
986 mutex_lock(&core->lock);
987 list_for_each_entry(inst, &core->instances, list)
988 if (hash32_ptr(inst) == session_id) {
989 mutex_unlock(&core->lock);
990 return inst;
991 }
992 mutex_unlock(&core->lock);
993
994 return NULL;
995 }
996
997 u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr)
998 {
999 const struct hfi_done_handler *handler;
1000 struct device *dev = core->dev;
1001 struct venus_inst *inst;
1002 bool found = false;
1003 unsigned int i;
1004
1005 for (i = 0; i < ARRAY_SIZE(handlers); i++) {
1006 handler = &handlers[i];
1007 if (handler->pkt != hdr->pkt_type)
1008 continue;
1009 found = true;
1010 break;
1011 }
1012
1013 if (!found)
1014 return hdr->pkt_type;
1015
1016 if (hdr->size && hdr->size < handler->pkt_sz &&
1017 hdr->size < handler->pkt_sz2) {
1018 dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n",
1019 hdr->size, handler->pkt_sz, hdr->pkt_type);
1020
1021 return hdr->pkt_type;
1022 }
1023
1024 if (handler->is_sys_pkt) {
1025 inst = NULL;
1026 } else {
1027 struct hfi_session_pkt *pkt;
1028
1029 pkt = (struct hfi_session_pkt *)hdr;
1030 inst = to_instance(core, pkt->shdr.session_id);
1031
1032 if (!inst)
1033 dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n",
1034 pkt->shdr.session_id,
1035 handler ? handler->pkt : 0);
1036
1037 /*
1038 * Event of type HFI_EVENT_SYS_ERROR will not have any session
1039 * associated with it
1040 */
1041 if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) {
1042 dev_err(dev, "got invalid session id:%x\n",
1043 pkt->shdr.session_id);
1044 goto invalid_session;
1045 }
1046 }
1047
1048 handler->done(core, inst, hdr);
1049
1050 invalid_session:
1051 return hdr->pkt_type;
1052 }