File Index
Files and directories
Sign in
FILE

hfi_msgs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/qcom/venus/hfi_msgs.c 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
 22static 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
158error:
159	inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
160	inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
161}
162
163static 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
182static 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
194static void
195event_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
225static 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
253static 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
278done:
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
288static void
289sys_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
327done:
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
342static 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
363static 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
373static 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
386static 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
392static 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
401static unsigned int
402session_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
421static unsigned int
422session_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
453static 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
484done:
485	inst->error = error;
486	complete(&inst->done);
487}
488
489static 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);
510done:
511	inst->error = error;
512	complete(&inst->done);
513}
514
515static 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
524static 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
535static 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
545static 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
620done:
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
626static 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
635static 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
644static 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
653static 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
662static 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
671static 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
680static 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
689struct 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
697static 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
787void hfi_process_watchdog_timeout(struct venus_core *core)
788{
789	event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL);
790}
791
792static 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
807u32 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
860invalid_session:
861	return hdr->pkt_type;
862}
~/ Read-only file preview.