Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  skl-sst-utils.c - SKL sst utils functions
0004  *
0005  *  Copyright (C) 2016 Intel Corp
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/slab.h>
0010 #include <linux/uuid.h>
0011 #include "../common/sst-dsp.h"
0012 #include "../common/sst-dsp-priv.h"
0013 #include "skl.h"
0014 
0015 #define DEFAULT_HASH_SHA256_LEN 32
0016 
0017 /* FW Extended Manifest Header id = $AE1 */
0018 #define SKL_EXT_MANIFEST_HEADER_MAGIC   0x31454124
0019 
0020 union seg_flags {
0021     u32 ul;
0022     struct {
0023         u32 contents : 1;
0024         u32 alloc    : 1;
0025         u32 load     : 1;
0026         u32 read_only : 1;
0027         u32 code     : 1;
0028         u32 data     : 1;
0029         u32 _rsvd0   : 2;
0030         u32 type     : 4;
0031         u32 _rsvd1   : 4;
0032         u32 length   : 16;
0033     } r;
0034 } __packed;
0035 
0036 struct segment_desc {
0037     union seg_flags flags;
0038     u32 v_base_addr;
0039     u32 file_offset;
0040 };
0041 
0042 struct module_type {
0043     u32 load_type  : 4;
0044     u32 auto_start : 1;
0045     u32 domain_ll  : 1;
0046     u32 domain_dp  : 1;
0047     u32 rsvd       : 25;
0048 } __packed;
0049 
0050 struct adsp_module_entry {
0051     u32 struct_id;
0052     u8  name[8];
0053     u8  uuid[16];
0054     struct module_type type;
0055     u8  hash1[DEFAULT_HASH_SHA256_LEN];
0056     u32 entry_point;
0057     u16 cfg_offset;
0058     u16 cfg_count;
0059     u32 affinity_mask;
0060     u16 instance_max_count;
0061     u16 instance_bss_size;
0062     struct segment_desc segments[3];
0063 } __packed;
0064 
0065 struct adsp_fw_hdr {
0066     u32 id;
0067     u32 len;
0068     u8  name[8];
0069     u32 preload_page_count;
0070     u32 fw_image_flags;
0071     u32 feature_mask;
0072     u16 major;
0073     u16 minor;
0074     u16 hotfix;
0075     u16 build;
0076     u32 num_modules;
0077     u32 hw_buf_base;
0078     u32 hw_buf_length;
0079     u32 load_offset;
0080 } __packed;
0081 
0082 struct skl_ext_manifest_hdr {
0083     u32 id;
0084     u32 len;
0085     u16 version_major;
0086     u16 version_minor;
0087     u32 entries;
0088 };
0089 
0090 static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
0091 {
0092     int pvt_id;
0093 
0094     for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) {
0095         if (module->instance_id[pvt_id] == instance_id)
0096             return pvt_id;
0097     }
0098     return -EINVAL;
0099 }
0100 
0101 int skl_get_pvt_instance_id_map(struct skl_dev *skl,
0102                 int module_id, int instance_id)
0103 {
0104     struct uuid_module *module;
0105 
0106     list_for_each_entry(module, &skl->uuid_list, list) {
0107         if (module->id == module_id)
0108             return skl_get_pvtid_map(module, instance_id);
0109     }
0110 
0111     return -EINVAL;
0112 }
0113 EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map);
0114 
0115 static inline int skl_getid_32(struct uuid_module *module, u64 *val,
0116                 int word1_mask, int word2_mask)
0117 {
0118     int index, max_inst, pvt_id;
0119     u32 mask_val;
0120 
0121     max_inst =  module->max_instance;
0122     mask_val = (u32)(*val >> word1_mask);
0123 
0124     if (mask_val != 0xffffffff) {
0125         index = ffz(mask_val);
0126         pvt_id = index + word1_mask + word2_mask;
0127         if (pvt_id <= (max_inst - 1)) {
0128             *val |= 1ULL << (index + word1_mask);
0129             return pvt_id;
0130         }
0131     }
0132 
0133     return -EINVAL;
0134 }
0135 
0136 static inline int skl_pvtid_128(struct uuid_module *module)
0137 {
0138     int j, i, word1_mask, word2_mask = 0, pvt_id;
0139 
0140     for (j = 0; j < MAX_INSTANCE_BUFF; j++) {
0141         word1_mask = 0;
0142 
0143         for (i = 0; i < 2; i++) {
0144             pvt_id = skl_getid_32(module, &module->pvt_id[j],
0145                         word1_mask, word2_mask);
0146             if (pvt_id >= 0)
0147                 return pvt_id;
0148 
0149             word1_mask += 32;
0150             if ((word1_mask + word2_mask) >= module->max_instance)
0151                 return -EINVAL;
0152         }
0153 
0154         word2_mask += 64;
0155         if (word2_mask >= module->max_instance)
0156             return -EINVAL;
0157     }
0158 
0159     return -EINVAL;
0160 }
0161 
0162 /**
0163  * skl_get_pvt_id: generate a private id for use as module id
0164  *
0165  * @skl: driver context
0166  * @uuid_mod: module's uuid
0167  * @instance_id: module's instance id
0168  *
0169  * This generates a 128 bit private unique id for a module TYPE so that
0170  * module instance is unique
0171  */
0172 int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id)
0173 {
0174     struct uuid_module *module;
0175     int pvt_id;
0176 
0177     list_for_each_entry(module, &skl->uuid_list, list) {
0178         if (guid_equal(uuid_mod, &module->uuid)) {
0179 
0180             pvt_id = skl_pvtid_128(module);
0181             if (pvt_id >= 0) {
0182                 module->instance_id[pvt_id] = instance_id;
0183 
0184                 return pvt_id;
0185             }
0186         }
0187     }
0188 
0189     return -EINVAL;
0190 }
0191 EXPORT_SYMBOL_GPL(skl_get_pvt_id);
0192 
0193 /**
0194  * skl_put_pvt_id: free up the private id allocated
0195  *
0196  * @skl: driver context
0197  * @uuid_mod: module's uuid
0198  * @pvt_id: module pvt id
0199  *
0200  * This frees a 128 bit private unique id previously generated
0201  */
0202 int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id)
0203 {
0204     int i;
0205     struct uuid_module *module;
0206 
0207     list_for_each_entry(module, &skl->uuid_list, list) {
0208         if (guid_equal(uuid_mod, &module->uuid)) {
0209 
0210             if (*pvt_id != 0)
0211                 i = (*pvt_id) / 64;
0212             else
0213                 i = 0;
0214 
0215             module->pvt_id[i] &= ~(1 << (*pvt_id));
0216             *pvt_id = -1;
0217             return 0;
0218         }
0219     }
0220 
0221     return -EINVAL;
0222 }
0223 EXPORT_SYMBOL_GPL(skl_put_pvt_id);
0224 
0225 /*
0226  * Parse the firmware binary to get the UUID, module id
0227  * and loadable flags
0228  */
0229 int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
0230             unsigned int offset, int index)
0231 {
0232     struct adsp_fw_hdr *adsp_hdr;
0233     struct adsp_module_entry *mod_entry;
0234     int i, num_entry, size;
0235     const char *buf;
0236     struct skl_dev *skl = ctx->thread_context;
0237     struct uuid_module *module;
0238     struct firmware stripped_fw;
0239     unsigned int safe_file;
0240     int ret;
0241 
0242     /* Get the FW pointer to derive ADSP header */
0243     stripped_fw.data = fw->data;
0244     stripped_fw.size = fw->size;
0245 
0246     skl_dsp_strip_extended_manifest(&stripped_fw);
0247 
0248     buf = stripped_fw.data;
0249 
0250     /* check if we have enough space in file to move to header */
0251     safe_file = sizeof(*adsp_hdr) + offset;
0252     if (stripped_fw.size <= safe_file) {
0253         dev_err(ctx->dev, "Small fw file size, No space for hdr\n");
0254         return -EINVAL;
0255     }
0256 
0257     adsp_hdr = (struct adsp_fw_hdr *)(buf + offset);
0258 
0259     /* check 1st module entry is in file */
0260     safe_file += adsp_hdr->len + sizeof(*mod_entry);
0261     if (stripped_fw.size <= safe_file) {
0262         dev_err(ctx->dev, "Small fw file size, No module entry\n");
0263         return -EINVAL;
0264     }
0265 
0266     mod_entry = (struct adsp_module_entry *)(buf + offset + adsp_hdr->len);
0267 
0268     num_entry = adsp_hdr->num_modules;
0269 
0270     /* check all entries are in file */
0271     safe_file += num_entry * sizeof(*mod_entry);
0272     if (stripped_fw.size <= safe_file) {
0273         dev_err(ctx->dev, "Small fw file size, No modules\n");
0274         return -EINVAL;
0275     }
0276 
0277 
0278     /*
0279      * Read the UUID(GUID) from FW Manifest.
0280      *
0281      * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX
0282      * Populate the UUID table to store module_id and loadable flags
0283      * for the module.
0284      */
0285 
0286     for (i = 0; i < num_entry; i++, mod_entry++) {
0287         module = kzalloc(sizeof(*module), GFP_KERNEL);
0288         if (!module) {
0289             ret = -ENOMEM;
0290             goto free_uuid_list;
0291         }
0292 
0293         import_guid(&module->uuid, mod_entry->uuid);
0294 
0295         module->id = (i | (index << 12));
0296         module->is_loadable = mod_entry->type.load_type;
0297         module->max_instance = mod_entry->instance_max_count;
0298         size = sizeof(int) * mod_entry->instance_max_count;
0299         module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
0300         if (!module->instance_id) {
0301             ret = -ENOMEM;
0302             goto free_uuid_list;
0303         }
0304 
0305         list_add_tail(&module->list, &skl->uuid_list);
0306 
0307         dev_dbg(ctx->dev,
0308             "Adding uuid :%pUL   mod id: %d  Loadable: %d\n",
0309             &module->uuid, module->id, module->is_loadable);
0310     }
0311 
0312     return 0;
0313 
0314 free_uuid_list:
0315     skl_freeup_uuid_list(skl);
0316     return ret;
0317 }
0318 
0319 void skl_freeup_uuid_list(struct skl_dev *skl)
0320 {
0321     struct uuid_module *uuid, *_uuid;
0322 
0323     list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) {
0324         list_del(&uuid->list);
0325         kfree(uuid);
0326     }
0327 }
0328 
0329 /*
0330  * some firmware binary contains some extended manifest. This needs
0331  * to be stripped in that case before we load and use that image.
0332  *
0333  * Get the module id for the module by checking
0334  * the table for the UUID for the module
0335  */
0336 int skl_dsp_strip_extended_manifest(struct firmware *fw)
0337 {
0338     struct skl_ext_manifest_hdr *hdr;
0339 
0340     /* check if fw file is greater than header we are looking */
0341     if (fw->size < sizeof(hdr)) {
0342         pr_err("%s: Firmware file small, no hdr\n", __func__);
0343         return -EINVAL;
0344     }
0345 
0346     hdr = (struct skl_ext_manifest_hdr *)fw->data;
0347 
0348     if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) {
0349         fw->size -= hdr->len;
0350         fw->data += hdr->len;
0351     }
0352 
0353     return 0;
0354 }
0355 
0356 int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
0357     struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp,
0358     struct sst_dsp_device *skl_dev)
0359 {
0360     struct skl_dev *skl = *dsp;
0361     struct sst_dsp *sst;
0362 
0363     skl->dev = dev;
0364     skl_dev->thread_context = skl;
0365     INIT_LIST_HEAD(&skl->uuid_list);
0366     skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq);
0367     if (!skl->dsp) {
0368         dev_err(skl->dev, "%s: no device\n", __func__);
0369         return -ENODEV;
0370     }
0371 
0372     sst = skl->dsp;
0373     sst->fw_name = fw_name;
0374     sst->dsp_ops = dsp_ops;
0375     init_waitqueue_head(&skl->mod_load_wait);
0376     INIT_LIST_HEAD(&sst->module_list);
0377 
0378     skl->is_first_boot = true;
0379 
0380     return 0;
0381 }
0382 
0383 int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo,
0384         struct firmware *stripped_fw,
0385         unsigned int hdr_offset, int index)
0386 {
0387     int ret;
0388     struct sst_dsp *dsp = skl->dsp;
0389 
0390     if (linfo->fw == NULL) {
0391         ret = request_firmware(&linfo->fw, linfo->name,
0392                     skl->dev);
0393         if (ret < 0) {
0394             dev_err(skl->dev, "Request lib %s failed:%d\n",
0395                 linfo->name, ret);
0396             return ret;
0397         }
0398     }
0399 
0400     if (skl->is_first_boot) {
0401         ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index);
0402         if (ret < 0)
0403             return ret;
0404     }
0405 
0406     stripped_fw->data = linfo->fw->data;
0407     stripped_fw->size = linfo->fw->size;
0408     skl_dsp_strip_extended_manifest(stripped_fw);
0409 
0410     return 0;
0411 }
0412 
0413 void skl_release_library(struct skl_lib_info *linfo, int lib_count)
0414 {
0415     int i;
0416 
0417     /* library indices start from 1 to N. 0 represents base FW */
0418     for (i = 1; i < lib_count; i++) {
0419         if (linfo[i].fw) {
0420             release_firmware(linfo[i].fw);
0421             linfo[i].fw = NULL;
0422         }
0423     }
0424 }