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