clear-pkgs-linux-iot-lts2018/0306-ASoC-Intel-Skylake-add...

350 lines
9.5 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Pawse, GuruprasadX" <guruprasadx.pawse@intel.com>
Date: Mon, 30 Jan 2017 20:12:52 +0530
Subject: [PATCH] ASoC: Intel: Skylake: add sysfs files for firmware modules
This patch adds sysfs files for firmware modules.
Below is the structure of sysfs files created:
/sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/dsp/modules/<UUID>
|---id: module id
|---hash: module hash
|---loaded: module state loaded/unloaded
Change-Id: Ia097a3cc1409a33b2a82b1d1cdc634fb4b0eee90
Signed-off-by: Pawse, GuruprasadX <guruprasadx.pawse@intel.com>
Reviewed-on:
Reviewed-by: R, Dharageswari <dharageswari.r@intel.com>
Reviewed-by: Kp, Jeeja <jeeja.kp@intel.com>
Reviewed-by: Prodduvaka, Leoni
Tested-by: Sm, Bhadur A <bhadur.a.sm@intel.com>
---
sound/soc/intel/skylake/skl-messages.c | 1 +
sound/soc/intel/skylake/skl-pcm.c | 3 +
sound/soc/intel/skylake/skl-sst-dsp.h | 7 +
sound/soc/intel/skylake/skl-sst-ipc.h | 3 +
sound/soc/intel/skylake/skl-sst-utils.c | 222 +++++++++++++++++++++++-
5 files changed, 235 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index f4ebdce7446d..54bd83eb55b5 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -1164,6 +1164,7 @@ int skl_free_dsp(struct skl *skl)
/* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+ skl_module_sysfs_exit(skl->skl_sst);
ctx->dsp_ops->cleanup(bus->dev, ctx);
kfree(ctx->cores.state);
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 1457e351efc4..2da571f9c5f4 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1963,6 +1963,9 @@ static int skl_platform_soc_probe(struct snd_soc_component *component)
}
skl_get_probe_widget(component, skl);
+
+ /* create sysfs to list modules downloaded by driver */
+ skl_module_sysfs_init(skl->skl_sst, &component->dev->kobj);
}
pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 58c0c13c15aa..7be2cdeb85b6 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -137,6 +137,8 @@ struct skl_tlv_message {
#define DSP_BUF PAGE_SIZE
+#define DEFAULT_HASH_SHA256_LEN 32
+
enum skl_fw_info_type {
SKL_FW_VERSION = 0,
SKL_MEMORY_RECLAIMED,
@@ -218,6 +220,7 @@ struct uuid_module {
int *instance_id;
struct list_head list;
+ u8 hash[DEFAULT_HASH_SHA256_LEN];
};
struct skl_load_module_info {
@@ -301,4 +304,8 @@ int bxt_set_dsp_D0i0(struct sst_dsp *ctx);
int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx);
void bxt_set_dsp_D0i3(struct work_struct *work);
+
+int skl_module_sysfs_init(struct skl_sst *ctx, struct kobject *fw_modules_kobj);
+
+void skl_module_sysfs_exit(struct skl_sst *ctx);
#endif /*__SKL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index 7700b5c54934..f3b8d7bc68ec 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -247,6 +247,9 @@ struct skl_sst {
/* firmware configuration information */
struct skl_fw_property_info fw_property;
+
+ /* sysfs for module info */
+ struct skl_sysfs_tree *sysfs_tree;
};
struct skl_ipc_init_instance_msg {
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 2bd5565d5f80..0eaa88e6ae61 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -23,11 +23,35 @@
#define UUID_STR_SIZE 37
-#define DEFAULT_HASH_SHA256_LEN 32
/* FW Extended Manifest Header id = $AE1 */
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
+#define UUID_ATTR_RO(_name) \
+ struct uuid_attribute uuid_attr_##_name = __ATTR_RO(_name)
+
+struct skl_sysfs_tree {
+ struct kobject *dsp_kobj;
+ struct kobject *modules_kobj;
+ struct skl_sysfs_module **mod_obj;
+};
+
+struct skl_sysfs_module {
+ struct kobject kobj;
+ struct uuid_module *uuid_mod;
+ struct list_head *module_list;
+ int fw_ops_load_mod;
+};
+
+struct uuid_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct skl_sysfs_module *modinfo_obj,
+ struct uuid_attribute *attr, char *buf);
+ ssize_t (*store)(struct skl_sysfs_module *modinfo_obj,
+ struct uuid_attribute *attr, const char *buf,
+ size_t count);
+};
+
struct UUID {
u8 id[16];
};
@@ -319,6 +343,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
ret = -ENOMEM;
goto free_uuid_list;
}
+ memcpy(&module->hash, mod_entry->hash1, sizeof(module->hash));
list_add_tail(&module->list, &skl->uuid_list);
@@ -665,3 +690,198 @@ int skl_get_firmware_configuration(struct sst_dsp *ctx)
kfree(ipc_data);
return ret;
}
+
+static ssize_t uuid_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct uuid_attribute *uuid_attr =
+ container_of(attr, struct uuid_attribute, attr);
+ struct skl_sysfs_module *modinfo_obj =
+ container_of(kobj, struct skl_sysfs_module, kobj);
+
+ if (uuid_attr->show)
+ return uuid_attr->show(modinfo_obj, uuid_attr, buf);
+
+ return 0;
+}
+
+static const struct sysfs_ops uuid_sysfs_ops = {
+ .show = uuid_attr_show,
+};
+
+static void uuid_release(struct kobject *kobj)
+{
+ struct skl_sysfs_module *modinfo_obj =
+ container_of(kobj, struct skl_sysfs_module, kobj);
+
+ kfree(modinfo_obj);
+}
+
+static struct kobj_type uuid_ktype = {
+ .release = uuid_release,
+ .sysfs_ops = &uuid_sysfs_ops,
+};
+
+static ssize_t loaded_show(struct skl_sysfs_module *modinfo_obj,
+ struct uuid_attribute *attr, char *buf)
+{
+ struct skl_module_table *module_list;
+
+ if ((!modinfo_obj->fw_ops_load_mod) ||
+ (modinfo_obj->fw_ops_load_mod &&
+ !modinfo_obj->uuid_mod->is_loadable))
+ return sprintf(buf, "%d\n", true);
+
+ if (list_empty(modinfo_obj->module_list))
+ return sprintf(buf, "%d\n", false);
+
+ list_for_each_entry(module_list, modinfo_obj->module_list, list) {
+ if (module_list->mod_info->mod_id
+ == modinfo_obj->uuid_mod->id)
+ return sprintf(buf, "%d\n", module_list->usage_cnt);
+ }
+
+ return sprintf(buf, "%d\n", false);
+}
+
+static ssize_t hash_show(struct skl_sysfs_module *modinfo_obj,
+ struct uuid_attribute *attr, char *buf)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < DEFAULT_HASH_SHA256_LEN; i++)
+ ret += sprintf(buf + ret, "%d ",
+ modinfo_obj->uuid_mod->hash[i]);
+ ret += sprintf(buf + ret, "\n");
+
+ return ret;
+}
+
+
+static ssize_t id_show(struct skl_sysfs_module *modinfo_obj,
+ struct uuid_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", modinfo_obj->uuid_mod->id);
+}
+
+static UUID_ATTR_RO(loaded);
+static UUID_ATTR_RO(hash);
+static UUID_ATTR_RO(id);
+
+static struct attribute *modules_attrs[] = {
+ &uuid_attr_loaded.attr,
+ &uuid_attr_hash.attr,
+ &uuid_attr_id.attr,
+ NULL,
+};
+
+static const struct attribute_group uuid_group = {
+ .attrs = modules_attrs,
+};
+
+static void free_uuid_node(struct kobject *kobj,
+ const struct attribute_group *group)
+{
+ if (kobj) {
+ sysfs_remove_group(kobj, group);
+ kobject_put(kobj);
+ }
+}
+
+void skl_module_sysfs_exit(struct skl_sst *ctx)
+{
+ struct skl_sysfs_tree *tree = ctx->sysfs_tree;
+ struct skl_sysfs_module **m;
+
+ if (!tree)
+ return;
+
+ if (tree->mod_obj) {
+ for (m = tree->mod_obj; *m; m++)
+ free_uuid_node(&(*m)->kobj, &uuid_group);
+ kfree(tree->mod_obj);
+ }
+
+ if (tree->modules_kobj)
+ kobject_put(tree->modules_kobj);
+
+ if (tree->dsp_kobj)
+ kobject_put(tree->dsp_kobj);
+
+ kfree(tree);
+ ctx->sysfs_tree = NULL;
+}
+EXPORT_SYMBOL_GPL(skl_module_sysfs_exit);
+
+int skl_module_sysfs_init(struct skl_sst *ctx, struct kobject *kobj)
+{
+ struct uuid_module *module;
+ struct skl_sysfs_module *modinfo_obj;
+ char *uuid_name;
+ int count = 0;
+ int max_mod = 0;
+ int ret = 0;
+
+ if (list_empty(&ctx->uuid_list))
+ return 0;
+
+ ctx->sysfs_tree = kzalloc(sizeof(*ctx->sysfs_tree), GFP_KERNEL);
+ if (!ctx->sysfs_tree) {
+ ret = -ENOMEM;
+ goto err_sysfs_exit;
+ }
+
+ ctx->sysfs_tree->dsp_kobj = kobject_create_and_add("dsp", kobj);
+ if (!ctx->sysfs_tree->dsp_kobj)
+ goto err_sysfs_exit;
+
+ ctx->sysfs_tree->modules_kobj = kobject_create_and_add("modules",
+ ctx->sysfs_tree->dsp_kobj);
+ if (!ctx->sysfs_tree->modules_kobj)
+ goto err_sysfs_exit;
+
+ list_for_each_entry(module, &ctx->uuid_list, list)
+ max_mod++;
+
+ ctx->sysfs_tree->mod_obj = kcalloc(max_mod + 1,
+ sizeof(*ctx->sysfs_tree->mod_obj), GFP_KERNEL);
+ if (!ctx->sysfs_tree->mod_obj) {
+ ret = -ENOMEM;
+ goto err_sysfs_exit;
+ }
+
+ list_for_each_entry(module, &ctx->uuid_list, list) {
+ modinfo_obj = kzalloc(sizeof(*modinfo_obj), GFP_KERNEL);
+ if (!modinfo_obj) {
+ ret = -ENOMEM;
+ goto err_sysfs_exit;
+ }
+
+ uuid_name = kasprintf(GFP_KERNEL, "%pUL", &module->uuid);
+ ret = kobject_init_and_add(&modinfo_obj->kobj, &uuid_ktype,
+ ctx->sysfs_tree->modules_kobj, uuid_name);
+ if (ret < 0)
+ goto err_sysfs_exit;
+
+ ret = sysfs_create_group(&modinfo_obj->kobj, &uuid_group);
+ if (ret < 0)
+ goto err_sysfs_exit;
+
+ modinfo_obj->uuid_mod = module;
+ modinfo_obj->module_list = &ctx->dsp->module_list;
+ modinfo_obj->fw_ops_load_mod =
+ (ctx->dsp->fw_ops.load_mod == NULL) ? 0 : 1;
+
+ ctx->sysfs_tree->mod_obj[count] = modinfo_obj;
+ count++;
+ }
+
+ return 0;
+
+err_sysfs_exit:
+ skl_module_sysfs_exit(ctx);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_module_sysfs_init);
--
https://clearlinux.org