cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hfi_parser.c (7979B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2018 Linaro Ltd.
      4 *
      5 * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
      6 */
      7#include <linux/bitops.h>
      8#include <linux/kernel.h>
      9
     10#include "core.h"
     11#include "hfi_helper.h"
     12#include "hfi_parser.h"
     13
     14typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
     15		     unsigned int size);
     16
     17static void init_codecs(struct venus_core *core)
     18{
     19	struct hfi_plat_caps *caps = core->caps, *cap;
     20	unsigned long bit;
     21
     22	for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {
     23		cap = &caps[core->codecs_count++];
     24		cap->codec = BIT(bit);
     25		cap->domain = VIDC_SESSION_TYPE_DEC;
     26		cap->valid = false;
     27	}
     28
     29	for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) {
     30		cap = &caps[core->codecs_count++];
     31		cap->codec = BIT(bit);
     32		cap->domain = VIDC_SESSION_TYPE_ENC;
     33		cap->valid = false;
     34	}
     35}
     36
     37static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,
     38			   u32 codecs, u32 domain, func cb, void *data,
     39			   unsigned int size)
     40{
     41	struct hfi_plat_caps *cap;
     42	unsigned int i;
     43
     44	for (i = 0; i < caps_num; i++) {
     45		cap = &caps[i];
     46		if (cap->valid && cap->domain == domain)
     47			continue;
     48		if (cap->codec & codecs && cap->domain == domain)
     49			cb(cap, data, size);
     50	}
     51}
     52
     53static void
     54fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
     55{
     56	const u32 *type = data;
     57
     58	if (*type == HFI_BUFFER_MODE_DYNAMIC)
     59		cap->cap_bufs_mode_dynamic = true;
     60}
     61
     62static void
     63parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
     64{
     65	struct hfi_buffer_alloc_mode_supported *mode = data;
     66	u32 num_entries = mode->num_entries;
     67	u32 *type;
     68
     69	if (num_entries > MAX_ALLOC_MODE_ENTRIES)
     70		return;
     71
     72	type = mode->data;
     73
     74	while (num_entries--) {
     75		if (mode->buffer_type == HFI_BUFFER_OUTPUT ||
     76		    mode->buffer_type == HFI_BUFFER_OUTPUT2)
     77			for_each_codec(core->caps, ARRAY_SIZE(core->caps),
     78				       codecs, domain, fill_buf_mode, type, 1);
     79
     80		type++;
     81	}
     82}
     83
     84static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
     85			       unsigned int num)
     86{
     87	const struct hfi_profile_level *pl = data;
     88
     89	memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));
     90	cap->num_pl += num;
     91}
     92
     93static void
     94parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
     95{
     96	struct hfi_profile_level_supported *pl = data;
     97	struct hfi_profile_level *proflevel = pl->profile_level;
     98	struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};
     99
    100	if (pl->profile_count > HFI_MAX_PROFILE_COUNT)
    101		return;
    102
    103	memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));
    104
    105	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
    106		       fill_profile_level, pl_arr, pl->profile_count);
    107}
    108
    109static void
    110fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
    111{
    112	const struct hfi_capability *caps = data;
    113
    114	memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));
    115	cap->num_caps += num;
    116}
    117
    118static void
    119parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
    120{
    121	struct hfi_capabilities *caps = data;
    122	struct hfi_capability *cap = caps->data;
    123	u32 num_caps = caps->num_capabilities;
    124	struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};
    125
    126	if (num_caps > MAX_CAP_ENTRIES)
    127		return;
    128
    129	memcpy(caps_arr, cap, num_caps * sizeof(*cap));
    130
    131	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
    132		       fill_caps, caps_arr, num_caps);
    133}
    134
    135static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
    136			  unsigned int num_fmts)
    137{
    138	const struct raw_formats *formats = fmts;
    139
    140	memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));
    141	cap->num_fmts += num_fmts;
    142}
    143
    144static void
    145parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
    146{
    147	struct hfi_uncompressed_format_supported *fmt = data;
    148	struct hfi_uncompressed_plane_info *pinfo = fmt->plane_info;
    149	struct hfi_uncompressed_plane_constraints *constr;
    150	struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};
    151	u32 entries = fmt->format_entries;
    152	unsigned int i = 0;
    153	u32 num_planes;
    154
    155	while (entries) {
    156		num_planes = pinfo->num_planes;
    157
    158		rawfmts[i].fmt = pinfo->format;
    159		rawfmts[i].buftype = fmt->buffer_type;
    160		i++;
    161
    162		if (pinfo->num_planes > MAX_PLANES)
    163			break;
    164
    165		pinfo = (void *)pinfo + sizeof(*constr) * num_planes +
    166			2 * sizeof(u32);
    167		entries--;
    168	}
    169
    170	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
    171		       fill_raw_fmts, rawfmts, i);
    172}
    173
    174static void parse_codecs(struct venus_core *core, void *data)
    175{
    176	struct hfi_codec_supported *codecs = data;
    177
    178	core->dec_codecs = codecs->dec_codecs;
    179	core->enc_codecs = codecs->enc_codecs;
    180
    181	if (IS_V1(core)) {
    182		core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;
    183		core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
    184		core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
    185	}
    186}
    187
    188static void parse_max_sessions(struct venus_core *core, const void *data)
    189{
    190	const struct hfi_max_sessions_supported *sessions = data;
    191
    192	core->max_sessions_supported = sessions->max_sessions;
    193}
    194
    195static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
    196{
    197	struct hfi_codec_mask_supported *mask = data;
    198
    199	*codecs = mask->codecs;
    200	*domain = mask->video_domains;
    201}
    202
    203static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
    204{
    205	if (!inst || !IS_V1(inst->core))
    206		return;
    207
    208	*codecs = inst->hfi_codec;
    209	*domain = inst->session_type;
    210}
    211
    212static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
    213{
    214	struct hfi_plat_caps *caps, *cap;
    215	unsigned int i;
    216	u32 dom;
    217
    218	if (!inst || !IS_V1(inst->core))
    219		return;
    220
    221	caps = inst->core->caps;
    222	dom = inst->session_type;
    223
    224	for (i = 0; i < MAX_CODEC_NUM; i++) {
    225		cap = &caps[i];
    226		if (cap->codec & codecs && cap->domain == dom)
    227			cap->valid = true;
    228	}
    229}
    230
    231static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
    232{
    233	const struct hfi_platform *plat;
    234	const struct hfi_plat_caps *caps = NULL;
    235	u32 enc_codecs, dec_codecs, count = 0;
    236	unsigned int entries;
    237
    238	plat = hfi_platform_get(core->res->hfi_version);
    239	if (!plat)
    240		return -EINVAL;
    241
    242	if (inst)
    243		return 0;
    244
    245	if (plat->codecs)
    246		plat->codecs(&enc_codecs, &dec_codecs, &count);
    247
    248	if (plat->capabilities)
    249		caps = plat->capabilities(&entries);
    250
    251	if (!caps || !entries || !count)
    252		return -EINVAL;
    253
    254	core->enc_codecs = enc_codecs;
    255	core->dec_codecs = dec_codecs;
    256	core->codecs_count = count;
    257	core->max_sessions_supported = MAX_SESSIONS;
    258	memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
    259	memcpy(core->caps, caps, sizeof(*caps) * entries);
    260
    261	return 0;
    262}
    263
    264u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
    265	       u32 size)
    266{
    267	unsigned int words_count = size >> 2;
    268	u32 *word = buf, *data, codecs = 0, domain = 0;
    269	int ret;
    270
    271	ret = hfi_platform_parser(core, inst);
    272	if (!ret)
    273		return HFI_ERR_NONE;
    274
    275	if (size % 4)
    276		return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
    277
    278	parser_init(inst, &codecs, &domain);
    279
    280	if (core->res->hfi_version > HFI_VERSION_1XX) {
    281		core->codecs_count = 0;
    282		memset(core->caps, 0, sizeof(core->caps));
    283	}
    284
    285	while (words_count) {
    286		data = word + 1;
    287
    288		switch (*word) {
    289		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
    290			parse_codecs(core, data);
    291			init_codecs(core);
    292			break;
    293		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
    294			parse_max_sessions(core, data);
    295			break;
    296		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
    297			parse_codecs_mask(&codecs, &domain, data);
    298			break;
    299		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
    300			parse_raw_formats(core, codecs, domain, data);
    301			break;
    302		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
    303			parse_caps(core, codecs, domain, data);
    304			break;
    305		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
    306			parse_profile_level(core, codecs, domain, data);
    307			break;
    308		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
    309			parse_alloc_mode(core, codecs, domain, data);
    310			break;
    311		default:
    312			break;
    313		}
    314
    315		word++;
    316		words_count--;
    317	}
    318
    319	if (!core->max_sessions_supported)
    320		core->max_sessions_supported = MAX_SESSIONS;
    321
    322	parser_fini(inst, codecs, domain);
    323
    324	return HFI_ERR_NONE;
    325}