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 * @mconfig: module configuration data 182 * 183 * This generates a 128 bit private unique id for a module TYPE so that 184 * module instance is unique 185 */ 186 int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id) 187 { 188 struct uuid_module *module; 189 int pvt_id; 190 191 list_for_each_entry(module, &ctx->uuid_list, list) { 192 if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 193 194 pvt_id = skl_pvtid_128(module); 195 if (pvt_id >= 0) { 196 module->instance_id[pvt_id] = instance_id; 197 198 return pvt_id; 199 } 200 } 201 } 202 203 return -EINVAL; 204 } 205 EXPORT_SYMBOL_GPL(skl_get_pvt_id); 206 207 /** 208 * skl_put_pvt_id: free up the private id allocated 209 * 210 * @ctx: driver context 211 * @mconfig: module configuration data 212 * 213 * This frees a 128 bit private unique id previously generated 214 */ 215 int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id) 216 { 217 int i; 218 struct uuid_module *module; 219 220 list_for_each_entry(module, &ctx->uuid_list, list) { 221 if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 222 223 if (*pvt_id != 0) 224 i = (*pvt_id) / 64; 225 else 226 i = 0; 227 228 module->pvt_id[i] &= ~(1 << (*pvt_id)); 229 *pvt_id = -1; 230 return 0; 231 } 232 } 233 234 return -EINVAL; 235 } 236 EXPORT_SYMBOL_GPL(skl_put_pvt_id); 237 238 /* 239 * Parse the firmware binary to get the UUID, module id 240 * and loadable flags 241 */ 242 int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, 243 unsigned int offset, int index) 244 { 245 struct adsp_fw_hdr *adsp_hdr; 246 struct adsp_module_entry *mod_entry; 247 int i, num_entry, size; 248 uuid_le *uuid_bin; 249 const char *buf; 250 struct skl_sst *skl = ctx->thread_context; 251 struct uuid_module *module; 252 struct firmware stripped_fw; 253 unsigned int safe_file; 254 255 /* Get the FW pointer to derive ADSP header */ 256 stripped_fw.data = fw->data; 257 stripped_fw.size = fw->size; 258 259 skl_dsp_strip_extended_manifest(&stripped_fw); 260 261 buf = stripped_fw.data; 262 263 /* check if we have enough space in file to move to header */ 264 safe_file = sizeof(*adsp_hdr) + offset; 265 if (stripped_fw.size <= safe_file) { 266 dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); 267 return -EINVAL; 268 } 269 270 adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); 271 272 /* check 1st module entry is in file */ 273 safe_file += adsp_hdr->len + sizeof(*mod_entry); 274 if (stripped_fw.size <= safe_file) { 275 dev_err(ctx->dev, "Small fw file size, No module entry\n"); 276 return -EINVAL; 277 } 278 279 mod_entry = (struct adsp_module_entry *) 280 (buf + offset + adsp_hdr->len); 281 282 num_entry = adsp_hdr->num_modules; 283 284 /* check all entries are in file */ 285 safe_file += num_entry * sizeof(*mod_entry); 286 if (stripped_fw.size <= safe_file) { 287 dev_err(ctx->dev, "Small fw file size, No modules\n"); 288 return -EINVAL; 289 } 290 291 292 /* 293 * Read the UUID(GUID) from FW Manifest. 294 * 295 * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX 296 * Populate the UUID table to store module_id and loadable flags 297 * for the module. 298 */ 299 300 for (i = 0; i < num_entry; i++, mod_entry++) { 301 module = kzalloc(sizeof(*module), GFP_KERNEL); 302 if (!module) 303 return -ENOMEM; 304 305 uuid_bin = (uuid_le *)mod_entry->uuid.id; 306 memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); 307 308 module->id = (i | (index << 12)); 309 module->is_loadable = mod_entry->type.load_type; 310 module->max_instance = mod_entry->instance_max_count; 311 size = sizeof(int) * mod_entry->instance_max_count; 312 module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); 313 if (!module->instance_id) { 314 kfree(module); 315 return -ENOMEM; 316 } 317 318 list_add_tail(&module->list, &skl->uuid_list); 319 320 dev_dbg(ctx->dev, 321 "Adding uuid :%pUL mod id: %d Loadable: %d\n", 322 &module->uuid, module->id, module->is_loadable); 323 } 324 325 return 0; 326 } 327 328 void skl_freeup_uuid_list(struct skl_sst *ctx) 329 { 330 struct uuid_module *uuid, *_uuid; 331 332 list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { 333 list_del(&uuid->list); 334 kfree(uuid); 335 } 336 } 337 338 /* 339 * some firmware binary contains some extended manifest. This needs 340 * to be stripped in that case before we load and use that image. 341 * 342 * Get the module id for the module by checking 343 * the table for the UUID for the module 344 */ 345 int skl_dsp_strip_extended_manifest(struct firmware *fw) 346 { 347 struct skl_ext_manifest_hdr *hdr; 348 349 /* check if fw file is greater than header we are looking */ 350 if (fw->size < sizeof(hdr)) { 351 pr_err("%s: Firmware file small, no hdr\n", __func__); 352 return -EINVAL; 353 } 354 355 hdr = (struct skl_ext_manifest_hdr *)fw->data; 356 357 if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { 358 fw->size -= hdr->len; 359 fw->data += hdr->len; 360 } 361 362 return 0; 363 } 364 365 int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, 366 struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, 367 struct sst_dsp_device *skl_dev) 368 { 369 struct skl_sst *skl; 370 struct sst_dsp *sst; 371 int ret; 372 373 skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); 374 if (skl == NULL) 375 return -ENOMEM; 376 377 skl->dev = dev; 378 skl_dev->thread_context = skl; 379 INIT_LIST_HEAD(&skl->uuid_list); 380 skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq); 381 if (!skl->dsp) { 382 dev_err(skl->dev, "%s: no device\n", __func__); 383 return -ENODEV; 384 } 385 386 sst = skl->dsp; 387 sst->fw_name = fw_name; 388 sst->dsp_ops = dsp_ops; 389 init_waitqueue_head(&skl->mod_load_wait); 390 INIT_LIST_HEAD(&sst->module_list); 391 ret = skl_ipc_init(dev, skl); 392 if (ret) 393 return ret; 394 395 skl->is_first_boot = true; 396 if (dsp) 397 *dsp = skl; 398 399 return ret; 400 } 401 402 int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, 403 struct firmware *stripped_fw, 404 unsigned int hdr_offset, int index) 405 { 406 int ret; 407 struct sst_dsp *dsp = skl->dsp; 408 409 if (linfo->fw == NULL) { 410 ret = request_firmware(&linfo->fw, linfo->name, 411 skl->dev); 412 if (ret < 0) { 413 dev_err(skl->dev, "Request lib %s failed:%d\n", 414 linfo->name, ret); 415 return ret; 416 } 417 } 418 419 if (skl->is_first_boot) { 420 ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index); 421 if (ret < 0) 422 return ret; 423 } 424 425 stripped_fw->data = linfo->fw->data; 426 stripped_fw->size = linfo->fw->size; 427 skl_dsp_strip_extended_manifest(stripped_fw); 428 429 return 0; 430 } 431 432 void skl_release_library(struct skl_lib_info *linfo, int lib_count) 433 { 434 int i; 435 436 /* library indices start from 1 to N. 0 represents base FW */ 437 for (i = 1; i < lib_count; i++) { 438 if (linfo[i].fw) { 439 release_firmware(linfo[i].fw); 440 linfo[i].fw = NULL; 441 } 442 } 443 } 444