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