]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/qcom/venus/hfi_msgs.c
Merge tag 'vfio-v4.13-rc1' of git://github.com/awilliam/linux-vfio
[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                         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 }