brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 41cc763 Raw
319 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright(c) 2024 Intel Corporation */3 4#include <linux/slab.h>5#include <linux/types.h>6#include "adf_mstate_mgr.h"7 8#define ADF_MSTATE_MAGIC	0xADF5CAEA9#define ADF_MSTATE_VERSION	0x110 11struct adf_mstate_sect_h {12	u8 id[ADF_MSTATE_ID_LEN];13	u32 size;14	u32 sub_sects;15	u8 state[];16};17 18u32 adf_mstate_state_size(struct adf_mstate_mgr *mgr)19{20	return mgr->state - mgr->buf;21}22 23static inline u32 adf_mstate_avail_room(struct adf_mstate_mgr *mgr)24{25	return mgr->buf + mgr->size - mgr->state;26}27 28void adf_mstate_mgr_init(struct adf_mstate_mgr *mgr, u8 *buf, u32 size)29{30	mgr->buf = buf;31	mgr->state = buf;32	mgr->size = size;33	mgr->n_sects = 0;34};35 36struct adf_mstate_mgr *adf_mstate_mgr_new(u8 *buf, u32 size)37{38	struct adf_mstate_mgr *mgr;39 40	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);41	if (!mgr)42		return NULL;43 44	adf_mstate_mgr_init(mgr, buf, size);45 46	return mgr;47}48 49void adf_mstate_mgr_destroy(struct adf_mstate_mgr *mgr)50{51	kfree(mgr);52}53 54void adf_mstate_mgr_init_from_parent(struct adf_mstate_mgr *mgr,55				     struct adf_mstate_mgr *p_mgr)56{57	adf_mstate_mgr_init(mgr, p_mgr->state,58			    p_mgr->size - adf_mstate_state_size(p_mgr));59}60 61void adf_mstate_mgr_init_from_psect(struct adf_mstate_mgr *mgr,62				    struct adf_mstate_sect_h *p_sect)63{64	adf_mstate_mgr_init(mgr, p_sect->state, p_sect->size);65	mgr->n_sects = p_sect->sub_sects;66}67 68static void adf_mstate_preamble_init(struct adf_mstate_preh *preamble)69{70	preamble->magic = ADF_MSTATE_MAGIC;71	preamble->version = ADF_MSTATE_VERSION;72	preamble->preh_len = sizeof(*preamble);73	preamble->size = 0;74	preamble->n_sects = 0;75}76 77/* default preambles checker */78static int adf_mstate_preamble_def_checker(struct adf_mstate_preh *preamble,79					   void *opaque)80{81	struct adf_mstate_mgr *mgr = opaque;82 83	if (preamble->magic != ADF_MSTATE_MAGIC ||84	    preamble->version > ADF_MSTATE_VERSION ||85	    preamble->preh_len > mgr->size) {86		pr_debug("QAT: LM - Invalid state (magic=%#x, version=%#x, hlen=%u), state_size=%u\n",87			 preamble->magic, preamble->version, preamble->preh_len,88			 mgr->size);89		return -EINVAL;90	}91 92	return 0;93}94 95struct adf_mstate_preh *adf_mstate_preamble_add(struct adf_mstate_mgr *mgr)96{97	struct adf_mstate_preh *pre = (struct adf_mstate_preh *)mgr->buf;98 99	if (adf_mstate_avail_room(mgr) < sizeof(*pre)) {100		pr_err("QAT: LM - Not enough space for preamble\n");101		return NULL;102	}103 104	adf_mstate_preamble_init(pre);105	mgr->state += pre->preh_len;106 107	return pre;108}109 110int adf_mstate_preamble_update(struct adf_mstate_mgr *mgr)111{112	struct adf_mstate_preh *preamble = (struct adf_mstate_preh *)mgr->buf;113 114	preamble->size = adf_mstate_state_size(mgr) - preamble->preh_len;115	preamble->n_sects = mgr->n_sects;116 117	return 0;118}119 120static void adf_mstate_dump_sect(struct adf_mstate_sect_h *sect,121				 const char *prefix)122{123	pr_debug("QAT: LM - %s QAT state section %s\n", prefix, sect->id);124	print_hex_dump_debug("h-", DUMP_PREFIX_OFFSET, 16, 2, sect,125			     sizeof(*sect), true);126	print_hex_dump_debug("s-", DUMP_PREFIX_OFFSET, 16, 2, sect->state,127			     sect->size, true);128}129 130static inline void __adf_mstate_sect_update(struct adf_mstate_mgr *mgr,131					    struct adf_mstate_sect_h *sect,132					    u32 size,133					    u32 n_subsects)134{135	sect->size += size;136	sect->sub_sects += n_subsects;137	mgr->n_sects++;138	mgr->state += sect->size;139 140	adf_mstate_dump_sect(sect, "Add");141}142 143void adf_mstate_sect_update(struct adf_mstate_mgr *p_mgr,144			    struct adf_mstate_mgr *curr_mgr,145			    struct adf_mstate_sect_h *sect)146{147	__adf_mstate_sect_update(p_mgr, sect, adf_mstate_state_size(curr_mgr),148				 curr_mgr->n_sects);149}150 151static struct adf_mstate_sect_h *adf_mstate_sect_add_header(struct adf_mstate_mgr *mgr,152							    const char *id)153{154	struct adf_mstate_sect_h *sect = (struct adf_mstate_sect_h *)(mgr->state);155 156	if (adf_mstate_avail_room(mgr) < sizeof(*sect)) {157		pr_debug("QAT: LM - Not enough space for header of QAT state sect %s\n", id);158		return NULL;159	}160 161	strscpy(sect->id, id, sizeof(sect->id));162	sect->size = 0;163	sect->sub_sects = 0;164	mgr->state += sizeof(*sect);165 166	return sect;167}168 169struct adf_mstate_sect_h *adf_mstate_sect_add_vreg(struct adf_mstate_mgr *mgr,170						   const char *id,171						   struct adf_mstate_vreginfo *info)172{173	struct adf_mstate_sect_h *sect;174 175	sect = adf_mstate_sect_add_header(mgr, id);176	if (!sect)177		return NULL;178 179	if (adf_mstate_avail_room(mgr) < info->size) {180		pr_debug("QAT: LM - Not enough space for QAT state sect %s, requires %u\n",181			 id, info->size);182		return NULL;183	}184 185	memcpy(sect->state, info->addr, info->size);186	__adf_mstate_sect_update(mgr, sect, info->size, 0);187 188	return sect;189}190 191struct adf_mstate_sect_h *adf_mstate_sect_add(struct adf_mstate_mgr *mgr,192					      const char *id,193					      adf_mstate_populate populate,194					      void *opaque)195{196	struct adf_mstate_mgr sub_sects_mgr;197	struct adf_mstate_sect_h *sect;198	int avail_room, size;199 200	sect = adf_mstate_sect_add_header(mgr, id);201	if (!sect)202		return NULL;203 204	if (!populate)205		return sect;206 207	avail_room = adf_mstate_avail_room(mgr);208	adf_mstate_mgr_init_from_parent(&sub_sects_mgr, mgr);209 210	size = (*populate)(&sub_sects_mgr, sect->state, avail_room, opaque);211	if (size < 0)212		return NULL;213 214	size += adf_mstate_state_size(&sub_sects_mgr);215	if (avail_room < size) {216		pr_debug("QAT: LM - Not enough space for QAT state sect %s, requires %u\n",217			 id, size);218		return NULL;219	}220	__adf_mstate_sect_update(mgr, sect, size, sub_sects_mgr.n_sects);221 222	return sect;223}224 225static int adf_mstate_sect_validate(struct adf_mstate_mgr *mgr)226{227	struct adf_mstate_sect_h *start = (struct adf_mstate_sect_h *)mgr->state;228	struct adf_mstate_sect_h *sect = start;229	u64 end;230	int i;231 232	end = (uintptr_t)mgr->buf + mgr->size;233	for (i = 0; i < mgr->n_sects; i++) {234		uintptr_t s_start = (uintptr_t)sect->state;235		uintptr_t s_end = s_start + sect->size;236 237		if (s_end < s_start || s_end > end) {238			pr_debug("QAT: LM - Corrupted state section (index=%u, size=%u) in state_mgr (size=%u, secs=%u)\n",239				 i, sect->size, mgr->size, mgr->n_sects);240			return -EINVAL;241		}242		sect = (struct adf_mstate_sect_h *)s_end;243	}244 245	pr_debug("QAT: LM - Scanned section (last child=%s, size=%lu) in state_mgr (size=%u, secs=%u)\n",246		 start->id, sizeof(struct adf_mstate_sect_h) * (ulong)(sect - start),247		 mgr->size, mgr->n_sects);248 249	return 0;250}251 252u32 adf_mstate_state_size_from_remote(struct adf_mstate_mgr *mgr)253{254	struct adf_mstate_preh *preh = (struct adf_mstate_preh *)mgr->buf;255 256	return preh->preh_len + preh->size;257}258 259int adf_mstate_mgr_init_from_remote(struct adf_mstate_mgr *mgr, u8 *buf, u32 size,260				    adf_mstate_preamble_checker pre_checker,261				    void *opaque)262{263	struct adf_mstate_preh *pre;264	int ret;265 266	adf_mstate_mgr_init(mgr, buf, size);267	pre = (struct adf_mstate_preh *)(mgr->buf);268 269	pr_debug("QAT: LM - Dump state preambles\n");270	print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 2, pre, pre->preh_len, 0);271 272	if (pre_checker)273		ret = (*pre_checker)(pre, opaque);274	else275		ret = adf_mstate_preamble_def_checker(pre, mgr);276	if (ret)277		return ret;278 279	mgr->state = mgr->buf + pre->preh_len;280	mgr->n_sects = pre->n_sects;281 282	return adf_mstate_sect_validate(mgr);283}284 285struct adf_mstate_sect_h *adf_mstate_sect_lookup(struct adf_mstate_mgr *mgr,286						 const char *id,287						 adf_mstate_action action,288						 void *opaque)289{290	struct adf_mstate_sect_h *sect = (struct adf_mstate_sect_h *)mgr->state;291	struct adf_mstate_mgr sub_sects_mgr;292	int i, ret;293 294	for (i = 0; i < mgr->n_sects; i++) {295		if (!strncmp(sect->id, id, sizeof(sect->id)))296			goto found;297 298		sect = (struct adf_mstate_sect_h *)(sect->state + sect->size);299	}300 301	return NULL;302 303found:304	adf_mstate_dump_sect(sect, "Found");305 306	adf_mstate_mgr_init_from_psect(&sub_sects_mgr, sect);307	if (sect->sub_sects && adf_mstate_sect_validate(&sub_sects_mgr))308		return NULL;309 310	if (!action)311		return sect;312 313	ret = (*action)(&sub_sects_mgr, sect->state, sect->size, opaque);314	if (ret)315		return NULL;316 317	return sect;318}319