]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/qcom/venus/hfi_msgs.c
Merge tag 'for-linus-20170812' of git://git.infradead.org/linux-mtd
[karo-tx-linux.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                         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 }