From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Wojciech Jablonski 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 Reviewed-by: Janca, Grzegorz Tested-by: Lewandowski, Gustaw --- .../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 #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