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