1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 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 0xADF5CAEA 9 #define ADF_MSTATE_VERSION 0x1 10 11 struct adf_mstate_sect_h { 12 u8 id[ADF_MSTATE_ID_LEN]; 13 u32 size; 14 u32 sub_sects; 15 u8 state[]; 16 }; 17 18 u32 adf_mstate_state_size(struct adf_mstate_mgr *mgr) 19 { 20 return mgr->state - mgr->buf; 21 } 22 23 static inline u32 adf_mstate_avail_room(struct adf_mstate_mgr *mgr) 24 { 25 return mgr->buf + mgr->size - mgr->state; 26 } 27 28 void 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 36 struct 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 49 void adf_mstate_mgr_destroy(struct adf_mstate_mgr *mgr) 50 { 51 kfree(mgr); 52 } 53 54 void 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 61 void 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 68 static 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 */ 78 static 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 95 struct 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 110 int 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 120 static 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 130 static 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 143 void 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 151 static 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 169 struct 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 191 struct 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 225 static 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 252 u32 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 259 int 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 else 275 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 285 struct 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 303 found: 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