1 /* 2 * skl-sst-utils.c - SKL sst utils functions 3 * 4 * Copyright (C) 2016 Intel Corp 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as version 2, as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 */ 15 16 #include <linux/device.h> 17 #include <linux/slab.h> 18 #include <linux/uuid.h> 19 #include "skl-sst-dsp.h" 20 #include "../common/sst-dsp.h" 21 #include "../common/sst-dsp-priv.h" 22 #include "skl-sst-ipc.h" 23 24 25 #define UUID_STR_SIZE 37 26 #define DEFAULT_HASH_SHA256_LEN 32 27 28 /* FW Extended Manifest Header id = $AE1 */ 29 #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 30 31 struct UUID { 32 u8 id[16]; 33 }; 34 35 union seg_flags { 36 u32 ul; 37 struct { 38 u32 contents : 1; 39 u32 alloc : 1; 40 u32 load : 1; 41 u32 read_only : 1; 42 u32 code : 1; 43 u32 data : 1; 44 u32 _rsvd0 : 2; 45 u32 type : 4; 46 u32 _rsvd1 : 4; 47 u32 length : 16; 48 } r; 49 } __packed; 50 51 struct segment_desc { 52 union seg_flags flags; 53 u32 v_base_addr; 54 u32 file_offset; 55 }; 56 57 struct module_type { 58 u32 load_type : 4; 59 u32 auto_start : 1; 60 u32 domain_ll : 1; 61 u32 domain_dp : 1; 62 u32 rsvd : 25; 63 } __packed; 64 65 struct adsp_module_entry { 66 u32 struct_id; 67 u8 name[8]; 68 struct UUID uuid; 69 struct module_type type; 70 u8 hash1[DEFAULT_HASH_SHA256_LEN]; 71 u32 entry_point; 72 u16 cfg_offset; 73 u16 cfg_count; 74 u32 affinity_mask; 75 u16 instance_max_count; 76 u16 instance_bss_size; 77 struct segment_desc segments[3]; 78 } __packed; 79 80 struct adsp_fw_hdr { 81 u32 id; 82 u32 len; 83 u8 name[8]; 84 u32 preload_page_count; 85 u32 fw_image_flags; 86 u32 feature_mask; 87 u16 major; 88 u16 minor; 89 u16 hotfix; 90 u16 build; 91 u32 num_modules; 92 u32 hw_buf_base; 93 u32 hw_buf_length; 94 u32 load_offset; 95 } __packed; 96 97 struct skl_ext_manifest_hdr { 98 u32 id; 99 u32 len; 100 u16 version_major; 101 u16 version_minor; 102 u32 entries; 103 }; 104 105 static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) 106 { 107 int pvt_id; 108 109 for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) { 110 if (module->instance_id[pvt_id] == instance_id) 111 return pvt_id; 112 } 113 return -EINVAL; 114 } 115 116 int skl_get_pvt_instance_id_map(struct skl_sst *ctx, 117 int module_id, int instance_id) 118 { 119 struct uuid_module *module; 120 121 list_for_each_entry(module, &ctx->uuid_list, list) { 122 if (module->id == module_id) 123 return skl_get_pvtid_map(module, instance_id); 124 } 125 126 return -EINVAL; 127 } 128 EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map); 129 130 static inline int skl_getid_32(struct uuid_module *module, u64 *val, 131 int word1_mask, int word2_mask) 132 { 133 int index, max_inst, pvt_id; 134 u32 mask_val; 135 136 max_inst = module->max_instance; 137 mask_val = (u32)(*val >> word1_mask); 138 139 if (mask_val != 0xffffffff) { 140 index = ffz(mask_val); 141 pvt_id = index + word1_mask + word2_mask; 142 if (pvt_id <= (max_inst - 1)) { 143 *val |= 1ULL << (index + word1_mask); 144 return pvt_id; 145 } 146 } 147 148 return -EINVAL; 149 } 150 151 static inline int skl_pvtid_128(struct uuid_module *module) 152 { 153 int j, i, word1_mask, word2_mask = 0, pvt_id; 154 155 for (j = 0; j < MAX_INSTANCE_BUFF; j++) { 156 word1_mask = 0; 157 158 for (i = 0; i < 2; i++) { 159 pvt_id = skl_getid_32(module, &module->pvt_id[j], 160 word1_mask, word2_mask); 161 if (pvt_id >= 0) 162 return pvt_id; 163 164 word1_mask += 32; 165 if ((word1_mask + word2_mask) >= module->max_instance) 166 return -EINVAL; 167 } 168 169 word2_mask += 64; 170 if (word2_mask >= module->max_instance) 171 return -EINVAL; 172 } 173 174 return -EINVAL; 175 } 176 177 /** 178 * skl_get_pvt_id: generate a private id for use as module id 179 * 180 * @ctx: driver context 181 * @uuid_mod: module's uuid 182 * @instance_id: module's instance id 183 * 184 * This generates a 128 bit private unique id for a module TYPE so that 185 * module instance is unique 186 */ 187 int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id) 188 { 189 struct uuid_module *module; 190 int pvt_id; 191 192 list_for_each_entry(module, &ctx->uuid_list, list) { 193 if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 194 195 pvt_id = skl_pvtid_128(module); 196 if (pvt_id >= 0) { 197 module->instance_id[pvt_id] = instance_id; 198 199 return pvt_id; 200 } 201 } 202 } 203 204 return -EINVAL; 205 } 206 EXPORT_SYMBOL_GPL(skl_get_pvt_id); 207 208 /** 209 * skl_put_pvt_id: free up the private id allocated 210 * 211 * @ctx: driver context 212 * @uuid_mod: module's uuid 213 * @pvt_id: module pvt id 214 * 215 * This frees a 128 bit private unique id previously generated 216 */ 217 int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id) 218 { 219 int i; 220 struct uuid_module *module; 221 222 list_for_each_entry(module, &ctx->uuid_list, list) { 223 if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 224 225 if (*pvt_id != 0) 226 i = (*pvt_id) / 64; 227 else 228 i = 0; 229 230 module->pvt_id[i] &= ~(1 << (*pvt_id)); 231 *pvt_id = -1; 232 return 0; 233 } 234 } 235 236 return -EINVAL; 237 } 238 EXPORT_SYMBOL_GPL(skl_put_pvt_id); 239 240 /* 241 * Parse the firmware binary to get the UUID, module id 242 * and loadable flags 243 */ 244 int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, 245 unsigned int offset, int index) 246 { 247 struct adsp_fw_hdr *adsp_hdr; 248 struct adsp_module_entry *mod_entry; 249 int i, num_entry, size; 250 uuid_le *uuid_bin; 251 const char *buf; 252 struct skl_sst *skl = ctx->thread_context; 253 struct uuid_module *module; 254 struct firmware stripped_fw; 255 unsigned int safe_file; 256 int ret = 0; 257 258 /* Get the FW pointer to derive ADSP header */ 259 stripped_fw.data = fw->data; 260 stripped_fw.size = fw->size; 261 262 skl_dsp_strip_extended_manifest(&stripped_fw); 263 264 buf = stripped_fw.data; 265 266 /* check if we have enough space in file to move to header */ 267 safe_file = sizeof(*adsp_hdr) + offset; 268 if (stripped_fw.size <= safe_file) { 269 dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); 270 return -EINVAL; 271 } 272 273 adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); 274 275 /* check 1st module entry is in file */ 276 safe_file += adsp_hdr->len + sizeof(*mod_entry); 277 if (stripped_fw.size <= safe_file) { 278 dev_err(ctx->dev, "Small fw file size, No module entry\n"); 279 return -EINVAL; 280 } 281 282 mod_entry = (struct adsp_module_entry *) 283 (buf + offset + adsp_hdr->len); 284 285 num_entry = adsp_hdr->num_modules; 286 287 /* check all entries are in file */ 288 safe_file += num_entry * sizeof(*mod_entry); 289 if (stripped_fw.size <= safe_file) { 290 dev_err(ctx->dev, "Small fw file size, No modules\n"); 291 return -EINVAL; 292 } 293 294 295 /* 296 * Read the UUID(GUID) from FW Manifest. 297 * 298 * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX 299 * Populate the UUID table to store module_id and loadable flags 300 * for the module. 301 */ 302 303 for (i = 0; i < num_entry; i++, mod_entry++) { 304 module = kzalloc(sizeof(*module), GFP_KERNEL); 305 if (!module) { 306 ret = -ENOMEM; 307 goto free_uuid_list; 308 } 309 310 uuid_bin = (uuid_le *)mod_entry->uuid.id; 311 memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); 312 313 module->id = (i | (index << 12)); 314 module->is_loadable = mod_entry->type.load_type; 315 module->max_instance = mod_entry->instance_max_count; 316 size = sizeof(int) * mod_entry->instance_max_count; 317 module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); 318 if (!module->instance_id) { 319 ret = -ENOMEM; 320 goto free_uuid_list; 321 } 322 323 list_add_tail(&module->list, &skl->uuid_list); 324 325 dev_dbg(ctx->dev, 326 "Adding uuid :%pUL mod id: %d Loadable: %d\n", 327 &module->uuid, module->id, module->is_loadable); 328 } 329 330 return 0; 331 332 free_uuid_list: 333 skl_freeup_uuid_list(skl); 334 return ret; 335 } 336 337 void skl_freeup_uuid_list(struct skl_sst *ctx) 338 { 339 struct uuid_module *uuid, *_uuid; 340 341 list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { 342 list_del(&uuid->list); 343 kfree(uuid); 344 } 345 } 346 347 /* 348 * some firmware binary contains some extended manifest. This needs 349 * to be stripped in that case before we load and use that image. 350 * 351 * Get the module id for the module by checking 352 * the table for the UUID for the module 353 */ 354 int skl_dsp_strip_extended_manifest(struct firmware *fw) 355 { 356 struct skl_ext_manifest_hdr *hdr; 357 358 /* check if fw file is greater than header we are looking */ 359 if (fw->size < sizeof(hdr)) { 360 pr_err("%s: Firmware file small, no hdr\n", __func__); 361 return -EINVAL; 362 } 363 364 hdr = (struct skl_ext_manifest_hdr *)fw->data; 365 366 if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { 367 fw->size -= hdr->len; 368 fw->data += hdr->len; 369 } 370 371 return 0; 372 } 373 374 int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, 375 struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, 376 struct sst_dsp_device *skl_dev) 377 { 378 struct skl_sst *skl; 379 struct sst_dsp *sst; 380 381 skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); 382 if (skl == NULL) 383 return -ENOMEM; 384 385 skl->dev = dev; 386 skl_dev->thread_context = skl; 387 INIT_LIST_HEAD(&skl->uuid_list); 388 skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq); 389 if (!skl->dsp) { 390 dev_err(skl->dev, "%s: no device\n", __func__); 391 return -ENODEV; 392 } 393 394 sst = skl->dsp; 395 sst->fw_name = fw_name; 396 sst->dsp_ops = dsp_ops; 397 init_waitqueue_head(&skl->mod_load_wait); 398 INIT_LIST_HEAD(&sst->module_list); 399 400 skl->is_first_boot = true; 401 if (dsp) 402 *dsp = skl; 403 404 return 0; 405 } 406 407 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, 408 struct firmware *stripped_fw, 409 unsigned int hdr_offset, int index) 410 { 411 int ret; 412 struct sst_dsp *dsp = skl->dsp; 413 414 if (linfo->fw == NULL) { 415 ret = request_firmware(&linfo->fw, linfo->name, 416 skl->dev); 417 if (ret < 0) { 418 dev_err(skl->dev, "Request lib %s failed:%d\n", 419 linfo->name, ret); 420 return ret; 421 } 422 } 423 424 if (skl->is_first_boot) { 425 ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index); 426 if (ret < 0) 427 return ret; 428 } 429 430 stripped_fw->data = linfo->fw->data; 431 stripped_fw->size = linfo->fw->size; 432 skl_dsp_strip_extended_manifest(stripped_fw); 433 434 return 0; 435 } 436 437 void skl_release_library(struct skl_lib_info *linfo, int lib_count) 438 { 439 int i; 440 441 /* library indices start from 1 to N. 0 represents base FW */ 442 for (i = 1; i < lib_count; i++) { 443 if (linfo[i].fw) { 444 release_firmware(linfo[i].fw); 445 linfo[i].fw = NULL; 446 } 447 } 448 } 449