clear-pkgs-linux-iot-lts2018/1004-ASoC-Intel-Skylake-Vir...

422 lines
12 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wojciech Jablonski <wojciech.jablonski@intel.com>
Date: Fri, 14 Dec 2018 12:46:49 +0100
Subject: [PATCH] ASoC: Intel: Skylake: Virt: Check domain_id during sync
kcontrol
Enable SOS to differentiate a kcontrol based on domain_id
If domain_id is associated with a GOS, then SOS synchronizes
the kcontrol with this GOS
Change-Id: I0ef7322f13a2ac16bd9679d03471ed761d0eaf9e
Tracked-On: OAM-76301
Signed-off-by: Jablonski, Wojciech <wojciech.jablonski@intel.com>
Reviewed-by: Janca, Grzegorz <grzegorz.janca@intel.com>
Tested-by: Lewandowski, Gustaw <gustaw.lewandowski@intel.com>
---
.../soc/intel/skylake/virtio/skl-virtio-be.c | 38 ++---
.../intel/skylake/virtio/skl-virtio-common.h | 14 +-
.../soc/intel/skylake/virtio/skl-virtio-fe.c | 27 ++--
.../intel/skylake/virtio/skl-virtio-kctl.c | 137 +++++++++++++++---
4 files changed, 149 insertions(+), 67 deletions(-)
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-be.c b/sound/soc/intel/skylake/virtio/skl-virtio-be.c
index c46d3964e7ae..8125cbde26df 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-be.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-be.c
@@ -636,7 +636,7 @@ static int vbe_skl_pcm_trigger(struct skl *sdev, int vm_id,
return rtd->ops.trigger(substream, cmd);
}
-static int vbe_skl_kcontrol_find_domain_id(const struct snd_kcontrol *kcontrol,
+static u32 vbe_skl_kcontrol_find_domain_id(const struct snd_kcontrol *kcontrol,
struct skl_module_cfg *mconfig)
{
struct skl_kctl_domain *domain;
@@ -652,13 +652,17 @@ static int vbe_skl_kcontrol_find_domain_id(const struct snd_kcontrol *kcontrol,
return 0;
}
-static int vbe_skl_kcontrol_get_domain_id(const struct skl *sdev,
- const struct snd_kcontrol *kcontrol, int *domain_id)
+static int vbe_skl_kcontrol_get_domain_id(const struct snd_kcontrol *kcontrol,
+ u32 *domain_id)
{
struct skl_module_cfg *mconfig;
struct snd_soc_dapm_widget *w;
void *priv = kcontrol->private_data;
int ret = 0;
+ struct skl *sdev = get_virtio_audio()->skl;
+
+ if (sdev == NULL)
+ return -EINVAL;
if (unlikely(!domain_id))
return -EINVAL;
@@ -679,26 +683,10 @@ static int vbe_skl_kcontrol_get_domain_id(const struct skl *sdev,
return 0;
}
-static int vbe_skl_kcontrol_check_permission(u32 domain_id,
- const struct snd_kcontrol *kcontrol)
-{
- int kcontrol_domain_id;
- int ret;
- struct skl *skl = get_virtio_audio()->skl;
-
- if (skl == NULL)
- return -EINVAL;
-
- ret = vbe_skl_kcontrol_get_domain_id(skl, kcontrol,
- &kcontrol_domain_id);
- if (ret < 0)
- return ret;
-
- if (kcontrol_domain_id != domain_id)
- return -EACCES;
-
- return 0;
-}
+static struct kctl_ops vbe_kctl_ops = {
+ .get_domain_id = vbe_skl_kcontrol_get_domain_id,
+ .send_noti = vbe_send_kctl_msg,
+};
static int vbe_skl_cfg_hda(const struct skl *sdev, int vm_id,
const struct vbe_ipc_msg *msg)
@@ -733,9 +721,7 @@ static int vbe_skl_msg_cfg_handle(struct snd_skl_vbe *vbe,
switch (msg->header->cmd) {
case VFE_MSG_CFG_HDA:
- kt_ops.check_permission = &vbe_skl_kcontrol_check_permission;
- kt_ops.send_noti = &vbe_send_kctl_msg;
- kctl_init_proxy(vbe->dev, &kt_ops);
+ kctl_init_proxy(vbe->dev, &vbe_kctl_ops);
kctl_notify_machine_ready(sdev->component->card);
return vbe_skl_cfg_hda(sdev, vm_id, msg);
default:
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-common.h b/sound/soc/intel/skylake/virtio/skl-virtio-common.h
index 97cb00e222ca..0ddb833aebc8 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-common.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-common.h
@@ -219,18 +219,24 @@ typedef int (*kctl_send_op)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct vfe_kctl_result *result);
-typedef int (*kctl_perm_op)(u32 domain_id,
- const struct snd_kcontrol *kcontrol);
+typedef int (*kctl_dom_op)(const struct snd_kcontrol *kcontrol,
+ u32 *domain_id);
struct kctl_ops {
kctl_send_op send_noti;
- kctl_perm_op check_permission;
+ kctl_dom_op get_domain_id;
+};
+
+struct kctl_domain {
+ u32 domain_id;
+ struct list_head kcontrols_list;
+ struct list_head list;
};
struct kctl_proxy {
struct device *alloc_dev;
struct kctl_ops ops;
- struct list_head kcontrols_list;
+ struct list_head domain_list;
};
struct kctl_proxy *get_kctl_proxy(void);
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
index 0e4505bd55ca..c530ccc7fc08 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
@@ -240,12 +240,6 @@ static int vfe_send_kctl_msg(struct snd_kcontrol *kcontrol,
sizeof(struct vfe_kctl_result));
}
-static int vfe_skl_kcontrol_check_permission(u32 domain_id,
- const struct snd_kcontrol *kcontrol)
-{
- return 0;
-}
-
static int vfe_put_inbox_buffer(struct snd_skl_vfe *vfe,
void *buff)
{
@@ -460,7 +454,7 @@ static void vfe_message_loop(struct work_struct *work)
break;
case VFE_MSG_KCTL_SET:
kctln = (struct vfe_kctl_noti *)header;
- kctl_ipc_handle(0u, &kctln->kcontrol,
+ kctl_ipc_handle(domain_id, &kctln->kcontrol,
&kctln->kcontrol_value, &result);
break;
case VFE_MSG_TPLG_DATA:
@@ -476,6 +470,18 @@ static void vfe_message_loop(struct work_struct *work)
vfe_put_inbox_buffer(vfe, header);
}
+static int vfe_skl_kcontrol_get_domain_id(const struct snd_kcontrol *kcontrol,
+ u32 *dom_id)
+{
+ *dom_id = domain_id;
+ return 0;
+}
+
+static struct kctl_ops vfe_kctl_ops = {
+ .get_domain_id = vfe_skl_kcontrol_get_domain_id,
+ .send_noti = vfe_send_kctl_msg,
+};
+
static struct vfe_msg_header
vfe_get_pcm_msg_header(enum vfe_ipc_msg_type msg_type,
struct snd_pcm_substream *substream)
@@ -1068,7 +1074,6 @@ static int vfe_init(struct virtio_device *vdev)
{
struct snd_skl_vfe *vfe;
int ret;
- struct kctl_ops kt_ops;
vfe = devm_kzalloc(&vdev->dev, sizeof(*vfe), GFP_KERNEL);
if (!vfe)
@@ -1091,7 +1096,7 @@ static int vfe_init(struct virtio_device *vdev)
INIT_WORK(&vfe->message_loop_work, vfe_message_loop);
- kctl_init_proxy(&vdev->dev, &kt_ops);
+ kctl_init_proxy(&vdev->dev, &vfe_kctl_ops);
vfe->send_dsp_ipc_msg = vfe_send_dsp_ipc_msg;
@@ -1101,10 +1106,6 @@ static int vfe_init(struct virtio_device *vdev)
if (ret < 0)
goto err;
- ret = vfe_skl_init(vdev);
- if (ret < 0)
- return ret;
-
return 0;
no_mem:
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-kctl.c b/sound/soc/intel/skylake/virtio/skl-virtio-kctl.c
index 01283716996e..c57ab912309e 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-kctl.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-kctl.c
@@ -15,17 +15,52 @@
#include <linux/device.h>
#include "skl-virtio-common.h"
-static struct kctl_wrapper *kctl_find_by_name(
- struct kctl_proxy *proxy, const char *kcontrol_name)
+static struct kctl_domain *find_domain(struct kctl_proxy *proxy,
+ u32 domain_id)
{
+ struct kctl_domain *domain;
+
+ list_for_each_entry(domain, &proxy->domain_list, list) {
+ if (domain->domain_id == domain_id)
+ return domain;
+ }
+ return NULL;
+}
+
+static struct kctl_domain *get_domain(struct kctl_proxy *proxy,
+ u32 domain_id)
+{
+ struct kctl_domain *domain = find_domain(proxy, domain_id);
+
+ if (domain == NULL) {
+ domain = devm_kzalloc(proxy->alloc_dev,
+ sizeof(*domain), GFP_KERNEL);
+
+ if (!domain)
+ return NULL;
+
+ domain->domain_id = domain_id;
+ list_add(&domain->list, &proxy->domain_list);
+ INIT_LIST_HEAD(&domain->kcontrols_list);
+ }
+
+ return domain;
+}
+
+static struct kctl_wrapper *kctl_find_by_name(struct kctl_proxy *proxy,
+ u32 domain_id, const char *kcontrol_name)
+{
+ struct kctl_domain *domain = find_domain(proxy, domain_id);
struct kctl_wrapper *kwrapper;
struct snd_kcontrol *kcontrol;
- list_for_each_entry(kwrapper, &proxy->kcontrols_list, list) {
- kcontrol = kwrapper->kcontrol;
- if (strncmp(kcontrol->id.name, kcontrol_name,
- ARRAY_SIZE(kcontrol->id.name)) == 0)
- return kwrapper;
+ if (domain) {
+ list_for_each_entry(kwrapper, &domain->kcontrols_list, list) {
+ kcontrol = kwrapper->kcontrol;
+ if (strncmp(kcontrol->id.name, kcontrol_name,
+ ARRAY_SIZE(kcontrol->id.name)) == 0)
+ return kwrapper;
+ }
}
return NULL;
}
@@ -34,19 +69,22 @@ void kctl_init_proxy(struct device *dev, struct kctl_ops *kt_ops)
{
struct kctl_proxy *proxy = get_kctl_proxy();
- INIT_LIST_HEAD(&proxy->kcontrols_list);
+ INIT_LIST_HEAD(&proxy->domain_list);
proxy->ops = *kt_ops;
proxy->alloc_dev = dev;
}
struct kctl_wrapper *kctl_find_by_address(struct kctl_proxy *proxy,
- struct snd_kcontrol *kcontrol)
+ u32 domain_id, struct snd_kcontrol *kcontrol)
{
+ struct kctl_domain *domain = find_domain(proxy, domain_id);
struct kctl_wrapper *kwrapper;
- list_for_each_entry(kwrapper, &proxy->kcontrols_list, list) {
- if (kcontrol == kwrapper->kcontrol)
- return kwrapper;
+ if (domain) {
+ list_for_each_entry(kwrapper, &domain->kcontrols_list, list) {
+ if (kcontrol == kwrapper->kcontrol)
+ return kwrapper;
+ }
}
return NULL;
}
@@ -54,12 +92,21 @@ struct kctl_wrapper *kctl_find_by_address(struct kctl_proxy *proxy,
int kctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ u32 domain_id;
struct vfe_kctl_result result;
struct kctl_proxy *proxy = get_kctl_proxy();
- struct kctl_wrapper *vfe_kcontrol =
- kctl_find_by_address(proxy, kcontrol);
+ struct kctl_wrapper *vfe_kcontrol;
int ret;
+ ret = proxy->ops.get_domain_id(kcontrol, &domain_id);
+ if (ret != 0)
+ return ret;
+
+ vfe_kcontrol = kctl_find_by_address(proxy, domain_id, kcontrol);
+
+ if (!vfe_kcontrol)
+ return -EPERM;
+
ret = proxy->ops.send_noti(kcontrol, ucontrol, &result);
if (ret < 0)
return ret;
@@ -76,7 +123,20 @@ int kctl_put(struct snd_kcontrol *kcontrol,
int kctl_wrap_kcontrol(struct kctl_proxy *proxy,
struct snd_kcontrol *kcontrol)
{
- struct kctl_wrapper *vfe_kcontrol = devm_kzalloc(proxy->alloc_dev,
+ u32 domain_id;
+ struct kctl_wrapper *vfe_kcontrol;
+ struct kctl_domain *domain;
+ int ret = proxy->ops.get_domain_id(kcontrol, &domain_id);
+
+ if ((ret != 0) || (domain_id == 0))
+ return ret;
+
+ domain = get_domain(proxy, domain_id);
+
+ if (!domain)
+ return -ENOMEM;
+
+ vfe_kcontrol = devm_kzalloc(proxy->alloc_dev,
sizeof(*vfe_kcontrol), GFP_KERNEL);
if (!vfe_kcontrol)
@@ -85,17 +145,49 @@ int kctl_wrap_kcontrol(struct kctl_proxy *proxy,
vfe_kcontrol->kcontrol = kcontrol;
vfe_kcontrol->put = kcontrol->put;
kcontrol->put = kctl_put;
+ //kcontrol->id.device = domain_id;
- list_add(&vfe_kcontrol->list, &proxy->kcontrols_list);
+ list_add(&vfe_kcontrol->list, &domain->kcontrols_list);
return 0;
}
+static void kctl_clean_list(struct list_head *kcontrols_list,
+ struct device *alloc_dev)
+{
+ struct kctl_wrapper *kwrapper;
+
+ while (!list_empty(kcontrols_list)) {
+ kwrapper = list_first_entry(kcontrols_list,
+ struct kctl_wrapper, list);
+ list_del(&kwrapper->list);
+ devm_kfree(alloc_dev, kwrapper);
+
+ }
+}
+
+static void kctl_clean_domain_list(struct kctl_proxy *proxy)
+{
+ struct kctl_domain *domain;
+
+ while (!list_empty(&proxy->domain_list)) {
+ domain = list_first_entry(&proxy->domain_list,
+ struct kctl_domain, list);
+ kctl_clean_list(&domain->kcontrols_list, proxy->alloc_dev);
+ list_del(&domain->kcontrols_list);
+ devm_kfree(proxy->alloc_dev, domain);
+
+ }
+}
+
void kctl_notify_machine_ready(struct snd_soc_card *card)
{
struct snd_kcontrol *kctl;
struct kctl_proxy *proxy = get_kctl_proxy();
int ret;
+ //to be sure if lis is empty
+ kctl_clean_domain_list(proxy);
+
list_for_each_entry(kctl, &card->snd_card->controls, list) {
ret = kctl_wrap_kcontrol(proxy, kctl);
if (ret < 0)
@@ -110,20 +202,17 @@ int kctl_ipc_handle(u32 domain_id, const struct vfe_kctl_info *kctl_info,
{
struct kctl_proxy *proxy = get_kctl_proxy();
struct kctl_wrapper *kcontrol =
- kctl_find_by_name(proxy, kctl_info->kcontrol_id);
+ kctl_find_by_name(proxy, domain_id, kctl_info->kcontrol_id);
int ret;
if (!kcontrol) {
- dev_err(proxy->alloc_dev, "Can not find kcontrol [%s].\n",
- kctl_info->kcontrol_id);
- ret = -ENODEV;
+ dev_err(proxy->alloc_dev,
+ "Can not find kcontrol [name=\"%s\", domain_id=%u].\n",
+ kctl_info->kcontrol_id, domain_id);
+ ret = -EPERM;
goto ret_result;
}
- ret = proxy->ops.check_permission(domain_id, kcontrol->kcontrol);
- if (ret < 0)
- goto ret_result;
-
if (kcontrol->put)
ret = kcontrol->put(kcontrol->kcontrol, &kcontrol_val->value);
--
https://clearlinux.org