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