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

1677 lines
45 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pawel Furtak <pawel.furtak@intel.com>
Date: Fri, 7 Dec 2018 12:17:00 +0100
Subject: [PATCH] ASoC: Intel: Skylake: Virt: Virtualization BE as module
Native driver should have no dependencies to virtualization layer.
This patch replaces explicit calls to register virt driver with
plugin mechanism and adapt virtualization BE service to the
mechanism.
To avoid security issues Guest OS should not have direct access to
topology file. Instead, it should send request to Service OS, which
will send proper topology for given GOS ID. This patch provide
such feature by introducing callback function for topology loading.
Service OS sets callback that has legacy implementation of topology
loading whereas Guest OS sets callback which acquires topology
through IPC.
Change-Id: I55135c11ddf509cf6d82160973080aca8d336707
Tracked-On: OAM-76301
Signed-off-by: Marcin Pietraszko <marcin.pietraszko@intel.com>
Signed-off-by: Furtak, Pawel <pawel.furtak@intel.com>
Reviewed-by: Janca, Grzegorz <grzegorz.janca@intel.com>
Tested-by: gkblditp <gkblditp@intel.com>
Reviewed-by: Wojciech Jablonski <wojciech.jablonski@intel.com>
---
sound/soc/intel/skylake/Makefile | 5 +-
sound/soc/intel/skylake/skl-sst-ipc.h | 5 +
sound/soc/intel/skylake/skl-topology.c | 2 +-
sound/soc/intel/skylake/skl.c | 54 +-
sound/soc/intel/skylake/skl.h | 22 +-
sound/soc/intel/skylake/virtio/Makefile | 13 +-
.../soc/intel/skylake/virtio/skl-virt-audio.c | 365 ++++++++++++++
.../soc/intel/skylake/virtio/skl-virtio-be.c | 146 +++++-
.../soc/intel/skylake/virtio/skl-virtio-be.h | 38 +-
.../intel/skylake/virtio/skl-virtio-common.h | 18 +
.../soc/intel/skylake/virtio/skl-virtio-fe.c | 93 +++-
.../soc/intel/skylake/virtio/skl-virtio-fe.h | 13 +
.../intel/skylake/virtio/skl-virtio-miscdev.c | 463 ------------------
sound/soc/intel/skylake/virtio/skl-virtio.h | 12 -
14 files changed, 733 insertions(+), 516 deletions(-)
create mode 100644 sound/soc/intel/skylake/virtio/skl-virt-audio.c
delete mode 100644 sound/soc/intel/skylake/virtio/skl-virtio-miscdev.c
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
index 66d2fd14f2c5..13ffff4bd1b1 100644
--- a/sound/soc/intel/skylake/Makefile
+++ b/sound/soc/intel/skylake/Makefile
@@ -2,8 +2,6 @@
snd-soc-skl-objs := skl.o skl-sdw-pcm.o skl-pcm.o skl-nhlt.o skl-messages.o \
skl-topology.o skl-compress.o skl-probe.o
-include sound/soc/intel/skylake/virtio/Makefile
-
ifdef CONFIG_DEBUG_FS
snd-soc-skl-objs += skl-debug.o
endif
@@ -23,3 +21,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK) += snd-soc-skl-ssp-clk.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_FE) += virtio/
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE) += virtio/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index ee32aaa68490..bff6c0c948b1 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -251,6 +251,8 @@ struct skl_notify_kctrl_info {
struct snd_kcontrol *notify_kctl;
};
+struct skl;
+
struct skl_sst {
struct device *dev;
struct sst_dsp *dsp;
@@ -304,6 +306,9 @@ struct skl_sst {
int num_sdw_controllers;
/* Array of sdw masters */
struct sdw_master *mstr;
+ void (*hda_irq_ack)(struct hdac_bus *bus, struct hdac_stream *hstr);
+
+ int (*request_tplg)(struct skl *skl, const struct firmware **fw);
struct skl_probe_config probe_config;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 84b9d001e35d..d0d4092b5807 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -5339,7 +5339,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
struct skl *skl = bus_to_skl(bus);
struct skl_pipeline *ppl;
- ret = request_firmware(&fw, skl->tplg_name, bus->dev);
+ ret = skl->skl_sst->request_tplg(skl, &fw);
if (ret < 0) {
dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
skl->tplg_name, ret);
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index deac8de7e125..c16ad3b65bb3 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -125,6 +125,12 @@ static void skl_clock_power_gating(struct device *dev, bool enable)
update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val);
}
+int skl_request_tplg(struct skl *skl, const struct firmware **fw)
+{
+ return request_firmware(fw, skl->tplg_name, skl->skl_sst->dev);
+}
+
+
/*
* While performing reset, controller may not come back properly causing
* issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
@@ -239,7 +245,6 @@ static void skl_dum_set(struct hdac_bus *bus)
static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
{
if (hstr->substream) {
- skl_notify_stream_update(bus, hstr->substream);
snd_pcm_period_elapsed(hstr->substream);
}
else if (hstr->stream) {
@@ -294,6 +299,7 @@ static irqreturn_t skl_interrupt(int irq, void *dev_id)
static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
{
struct hdac_bus *bus = dev_id;
+ struct skl *skl = bus_to_skl(bus);
u32 status;
u32 int_enable;
u32 mask;
@@ -301,7 +307,7 @@ static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
status = snd_hdac_chip_readl(bus, INTSTS);
- snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update);
+ snd_hdac_bus_handle_stream_irq(bus, status, skl->skl_sst->hda_irq_ack);
/* Re-enable stream interrupts */
mask = (0x1 << bus->num_streams) - 1;
@@ -582,6 +588,44 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
return 0;
}
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE)
+
+int skl_virt_device_register(struct skl *skl)
+{
+ struct hdac_bus *bus = skl_to_bus(skl);
+ struct platform_device *pdev;
+ struct skl_virt_pdata *pdata;
+ int ret;
+
+ pdev = platform_device_alloc("skl-virt-audio", -1);
+ if (pdev == NULL) {
+ dev_err(bus->dev, "platform device alloc failed\n");
+ return -EIO;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(bus->dev, "failed to add virtualization device\n");
+ platform_device_put(pdev);
+ return -EIO;
+ }
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct skl_virt_pdata), GFP_KERNEL);
+ pdata->skl = skl;
+ dev_set_drvdata(&pdev->dev, pdata);
+ skl->virt_dev = pdev;
+
+ return 0;
+}
+
+void skl_virt_device_unregister(struct skl *skl)
+{
+ if (skl->virt_dev)
+ platform_device_unregister(skl->virt_dev);
+}
+
+#endif
+
static int skl_machine_device_register(struct skl *skl)
{
struct hdac_bus *bus = skl_to_bus(skl);
@@ -1039,7 +1083,6 @@ static int skl_probe(struct pci_dev *pci,
err = skl_find_machine(skl, (void *)pci_id->driver_data);
if (err < 0)
goto out_nhlt_free;
-
err = skl_init_dsp(skl);
if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n");
@@ -1047,6 +1090,8 @@ static int skl_probe(struct pci_dev *pci,
}
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+ skl->skl_sst->request_tplg = skl_request_tplg;
+ skl->skl_sst->hda_irq_ack = skl_stream_update;
}
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
@@ -1058,7 +1103,7 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0)
goto out_dsp_free;
- snd_soc_skl_virtio_miscdev_register(skl);
+ skl_virt_device_register(skl);
schedule_work(&skl->probe_work);
return 0;
@@ -1124,6 +1169,7 @@ static void skl_remove(struct pci_dev *pci)
snd_hdac_ext_bus_device_remove(bus);
skl->debugfs = NULL;
+ skl_virt_device_unregister(skl);
skl_platform_unregister(&pci->dev);
skl_free_dsp(skl);
skl_machine_device_unregister(skl);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index ef02c70035b6..7915ef02a551 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -52,6 +52,21 @@
#define BXT_INSTANCE_ID 0
#define BXT_BASE_FW_MODULE_ID 0
+struct skl;
+
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE)
+int skl_virt_device_register(struct skl *skl);
+void skl_virt_device_unregister(struct skl *skl);
+#else
+static inline int skl_virt_device_register(struct skl *skl)
+{
+ return 0;
+}
+static inline void skl_virt_device_unregister(struct skl *skl)
+{
+}
+#endif
+
struct skl_dsp_resource {
u32 max_mcps;
u32 max_mem;
@@ -130,6 +145,7 @@ struct skl {
struct platform_device *dmic_dev;
struct platform_device *i2s_dev;
struct platform_device *clk_dev;
+ struct platform_device *virt_dev;
struct snd_soc_component *component;
struct snd_soc_dai_driver *dais;
@@ -159,9 +175,11 @@ struct skl {
bool nhlt_override;
bool mod_set_get_status;
struct ep_group_cnt grp_cnt;
+};
- /* list of virtual BE services */
- struct list_head vbe_list;
+struct skl_virt_pdata {
+ struct skl *skl;
+ void *private_data;
};
#define skl_to_bus(s) (&(s)->hbus)
diff --git a/sound/soc/intel/skylake/virtio/Makefile b/sound/soc/intel/skylake/virtio/Makefile
index 1c2aa5f6ba8d..ea15468907e6 100644
--- a/sound/soc/intel/skylake/virtio/Makefile
+++ b/sound/soc/intel/skylake/virtio/Makefile
@@ -1,11 +1,10 @@
-snd-soc-skl-virtio-sst-objs := virtio/skl-virtio-sst.o
-snd-soc-skl-virtio-card-objs := virtio/skl-virtio-card.o
-snd-soc-skl-virtio-fe-objs := virtio/skl-virtio-fe.o virtio/skl-virtio-kctl.o
+# SPDX-License-Identifier: GPL-2.0
+snd-soc-skl-virtio-sst-objs := skl-virtio-sst.o
+snd-soc-skl-virtio-card-objs := skl-virtio-card.o
+snd-soc-skl-virtio-fe-objs := skl-virtio-kctl.o skl-virtio-fe.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_FE) := snd-soc-skl-virtio-sst.o \
snd-soc-skl-virtio-fe.o snd-soc-skl-virtio-card.o
-ifdef CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE
-snd-soc-skl-objs += virtio/skl-virtio-be.o virtio/skl-virtio-miscdev.o \
-virtio/skl-virtio-kctl.o
-endif
+snd-soc-skl-virtio-be-objs := skl-virt-audio.o skl-virtio-kctl.o skl-virtio-be.o
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE) += snd-soc-skl-virtio-be.o
diff --git a/sound/soc/intel/skylake/virtio/skl-virt-audio.c b/sound/soc/intel/skylake/virtio/skl-virt-audio.c
new file mode 100644
index 000000000000..e2b288e8ba7e
--- /dev/null
+++ b/sound/soc/intel/skylake/virtio/skl-virt-audio.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// skl-virtio-miscdev.c -- Miscellaneous Virtio device for BE service
+//
+// Copyright (C) 2018 Intel Corporation.
+//
+// Authors: Furtak, Pawel <pawel.furtak@intel.com>
+// Janca, Grzegorz <grzegorz.janca@intel.com>
+//
+// This module registers a device node /dev/vbs_k_audio, that handle
+// the communication between Device Model and the virtio backend service.
+// The device model can control the backend to : set the status,
+// set the vq account and etc. The config of the DM and VBS must be accordance.
+
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+#include "skl-virtio-be.h"
+#include "skl-virtio.h"
+#include "../skl-sst-ipc.h"
+
+
+static struct vskl *virtio_audio;
+
+struct vskl *get_virtio_audio(void)
+{
+ return virtio_audio;
+}
+
+/* find client from client ID */
+static struct snd_skl_vbe_client *vbe_client_find(struct snd_skl_vbe *vbe,
+ int client_id)
+{
+ struct snd_skl_vbe_client *client;
+
+ list_for_each_entry(client, &vbe->client_list, list) {
+ if (client_id == client->vhm_client_id)
+ return client;
+ }
+
+ return NULL;
+}
+
+static int vskl_vbs_handle_kick(int client_id, unsigned long *ioreqs_map)
+{
+ struct vhm_request *req;
+ struct snd_skl_vbe_client *client;
+ int i, handle;
+ struct vskl *vskl = get_virtio_audio();
+ struct snd_skl_vbe *vbe = &vskl->vbe;
+
+ if (!vskl) {
+ pr_err("err: virtualization service not registred for skl");
+ return -EINVAL;
+ }
+
+ dev_dbg(vskl->dev, "virtio audio kick handling!\n");
+
+ /* get the client this notification is for/from? */
+ client = vbe_client_find(vbe, client_id);
+ if (!client) {
+ dev_err(vskl->dev, "Ooops! client %d not found!\n",
+ client_id);
+ return -EINVAL;
+ }
+
+ /* go through all vcpu for the valid request buffer */
+ for (i = 0; i < client->max_vcpu; i++) {
+ req = &client->req_buf[i];
+ handle = 0;
+
+ /* ignore if not processing state */
+ if (atomic_read(&req->processed) != REQ_STATE_PROCESSING)
+ continue;
+
+ dev_dbg(vskl->dev,
+ "ioreq type %d, direction %d, addr 0x%llx, size 0x%llx, value 0x%x\n",
+ req->type,
+ req->reqs.pio_request.direction,
+ req->reqs.pio_request.address,
+ req->reqs.pio_request.size,
+ req->reqs.pio_request.value);
+
+ if (req->reqs.pio_request.direction == REQUEST_READ) {
+ /*
+ * currently we handle kick only,
+ * so read will return 0
+ */
+ req->reqs.pio_request.value = 0;
+ } else {
+ req->reqs.pio_request.value >= 0 ?
+ (handle = 1) : (handle = 0);
+ }
+
+ atomic_set(&req->processed, REQ_STATE_COMPLETE);
+ acrn_ioreq_complete_request(client->vhm_client_id, i, req);
+
+ /* handle VQ kick if needed */
+ if (handle)
+ vbe_skl_handle_kick(vbe, req->reqs.pio_request.value);
+ }
+
+ return 0;
+}
+
+int vskl_vbs_init_be(struct vskl *vskl, struct snd_skl_vbe *vbe)
+{
+ struct virtio_vq_info *vqs;
+ struct device *dev = vskl->dev;
+ int i;
+
+ INIT_LIST_HEAD(&vbe->client_list);
+ INIT_LIST_HEAD(&vbe->substr_info_list);
+ INIT_LIST_HEAD(&vbe->pending_msg_list);
+ spin_lock_init(&vbe->posn_lock);
+ vbe->dev = dev;
+
+ vqs = vbe->vqs;
+ for (i = 0; i < SKL_VIRTIO_NUM_OF_VQS; i++) {
+ vqs[i].dev = &vbe->dev_info;
+ vqs[i].vq_notify = NULL;
+ }
+
+ /* link dev and vqs */
+ vbe->dev_info.vqs = vqs;
+ virtio_dev_init(&vbe->dev_info, vqs, SKL_VIRTIO_NUM_OF_VQS);
+
+ return 0;
+}
+
+/*
+ * register vhm client with virtio.
+ * vhm use the client to handle the io access from FE
+ */
+int vskl_vbs_register_client(struct snd_skl_vbe *vbe)
+{
+ struct virtio_dev_info *dev_info = &vbe->dev_info;
+ struct vm_info info;
+ struct snd_skl_vbe_client *client;
+ unsigned int vmid;
+ int ret;
+
+ /*
+ * vbs core has mechanism to manage the client
+ * there is no need to handle this in the special BE driver
+ * let's use the vbs core client management later
+ */
+ client = devm_kzalloc(vbe->dev, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -EINVAL;
+ client->vbe = vbe;
+
+ vmid = dev_info->_ctx.vmid;
+ client->vhm_client_id = acrn_ioreq_create_client(vmid,
+ vskl_vbs_handle_kick,
+ "snd_skl_vbe kick init\n");
+ if (client->vhm_client_id < 0) {
+ dev_err(vbe->dev, "failed to create client of acrn ioreq!\n");
+ return client->vhm_client_id;
+ }
+
+ ret = acrn_ioreq_add_iorange(client->vhm_client_id, REQ_PORTIO,
+ dev_info->io_range_start,
+ dev_info->io_range_start +
+ dev_info->io_range_len - 1);
+ if (ret < 0) {
+ dev_err(vbe->dev, "failed to add iorange to acrn ioreq!\n");
+ goto err;
+ }
+
+ /*
+ * setup the vm information, such as max_vcpu and max_gfn
+ * BE need this information to handle the vqs
+ */
+ ret = vhm_get_vm_info(vmid, &info);
+ if (ret < 0) {
+ dev_err(vbe->dev, "failed in vhm_get_vm_info!\n");
+ goto err;
+ }
+ client->max_vcpu = info.max_vcpu;
+
+ /* TODO: comment what this is doing */
+ client->req_buf = acrn_ioreq_get_reqbuf(client->vhm_client_id);
+ if (!client->req_buf) {
+ dev_err(vbe->dev, "failed in acrn_ioreq_get_reqbuf!\n");
+ goto err;
+ }
+
+ /* just attach once as vhm will kick kthread */
+ acrn_ioreq_attach_client(client->vhm_client_id, 0);
+
+ /* complete client init and add to list */
+ list_add(&client->list, &vbe->client_list);
+
+ return 0;
+err:
+ acrn_ioreq_destroy_client(client->vhm_client_id);
+ return -EINVAL;
+}
+
+static int vskl_vbs_audio_open(struct inode *inode, struct file *f)
+{
+ struct vskl *vskl = get_virtio_audio();
+
+ return vbe_skl_attach(&vskl->vbe, vskl->skl);
+}
+
+static long vskl_vbs_audio_ioctl(struct file *f, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct vskl *vskl = get_virtio_audio();
+ struct snd_skl_vbe *vbe = &vskl->vbe;
+ void __user *argp = (void __user *)arg;
+ int ret;
+
+ switch (ioctl) {
+ case VBS_SET_DEV:
+ ret = virtio_dev_ioctl(&vbe->dev_info, ioctl, argp);
+ if (!ret)
+ vbe->vmid = vbe->dev_info._ctx.vmid;
+ break;
+ case VBS_SET_VQ:
+ ret = virtio_vqs_ioctl(&vbe->dev_info, ioctl, argp);
+ if (ret)
+ return ret;
+
+ ret = vskl_vbs_register_client(vbe);
+ if (ret)
+ return ret;
+ break;
+ default:
+ pr_err("%s: Unsupported ioctl cmd[%d].\n",
+ __func__, ioctl);
+ return -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
+static int vskl_vbs_audio_release(struct inode *inode, struct file *f)
+{
+ struct vskl *vskl = get_virtio_audio();
+
+ return vbe_skl_detach(&vskl->vbe, vskl->skl);
+}
+
+static const struct file_operations vskl_vbs_audio_fops = {
+ .owner = THIS_MODULE,
+ .release = vskl_vbs_audio_release,
+ .unlocked_ioctl = vskl_vbs_audio_ioctl,
+ .open = vskl_vbs_audio_open,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice vskl_vbs_audio_k = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "vbs_k_audio",
+ .fops = &vskl_vbs_audio_fops,
+};
+
+static int vskl_vbs_init(struct vskl *vskl)
+{
+ int ret;
+
+ ret = misc_register(&vskl_vbs_audio_k);
+ if (ret < 0) {
+ dev_err(vskl->dev, "misc device register failed %d\n", ret);
+ return ret;
+ }
+
+ ret = vskl_vbs_init_be(vskl, &vskl->vbe);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int vskl_vbs_close(struct vskl *vskl)
+{
+ misc_deregister(&vskl_vbs_audio_k);
+
+ return vbe_skl_detach(&vskl->vbe, vskl->skl);
+}
+
+static int vskl_init(struct vskl *vskl, struct skl *skl, struct device *dev)
+{
+ int ret;
+
+ vskl->dev = dev;
+ vskl->skl = skl;
+
+ ret = vskl_vbs_init(vskl);
+ if (ret < 0) {
+ dev_err(vskl->dev,
+ "Failed to initialize BE service (error: %d)\n", ret);
+ return ret;
+ }
+
+ virtio_audio = vskl;
+
+ return 0;
+}
+
+static int vskl_close(struct vskl *vskl)
+{
+ /* For future use e.g. vhost implementation */
+ return vskl_vbs_close(vskl);
+}
+
+static int vskl_probe(struct platform_device *pdev)
+{
+ struct vskl *vskl;
+ int ret;
+ struct skl_virt_pdata *pdata = dev_get_drvdata(&pdev->dev);
+
+ if (!pdata || !pdata->skl) {
+ dev_err(&pdev->dev, "Failed to find native Skylake audio driver");
+ return -ENODEV;
+ }
+
+ vskl = devm_kzalloc(&pdev->dev, sizeof(*vskl), GFP_KERNEL);
+ if (!vskl)
+ return -ENOMEM;
+
+ ret = vskl_init(vskl, pdata->skl, &pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ pdata->private_data = vskl;
+
+ return 0;
+}
+
+static int vskl_remove(struct platform_device *pdev)
+{
+ int ret;
+ struct vskl *vskl;
+ struct skl_virt_pdata *pdata = dev_get_drvdata(&pdev->dev);
+
+ vskl = pdata->private_data;
+ if (!vskl)
+ return -EINVAL;
+
+ ret = vskl_close(vskl);
+ pdata->private_data = NULL;
+
+ return ret;
+}
+
+static struct platform_driver vskl_audio = {
+ .probe = vskl_probe,
+ .remove = vskl_remove,
+ .driver = {
+ .name = "skl-virt-audio",
+ },
+};
+module_platform_driver(vskl_audio)
+
+MODULE_DESCRIPTION("ASoC cAVS virtualization driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl-virt-audio");
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-be.c b/sound/soc/intel/skylake/virtio/skl-virtio-be.c
index 66eaf60fbad1..c46d3964e7ae 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-be.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-be.c
@@ -35,6 +35,16 @@
#include "../skl-topology.h"
#include "skl-virtio.h"
+static struct snd_skl_vbe *get_virtio_audio_be(void)
+{
+ return &get_virtio_audio()->vbe;
+}
+
+struct kctl_proxy *get_kctl_proxy(void)
+{
+ return &get_virtio_audio_be()->kcon_proxy;
+}
+
const struct vbe_substream_info *vbe_find_substream_info_by_pcm(
const struct snd_skl_vbe *vbe, char *pcm_id, int direction)
{
@@ -59,15 +69,9 @@ inline const struct vbe_substream_info *vbe_find_substream_info(
static const struct vbe_substream_info *vbe_skl_find_substream_info(
const struct skl *sdev, const struct snd_pcm_substream *substr)
{
- const struct snd_skl_vbe *vbe;
- const struct vbe_substream_info *info;
+ const struct snd_skl_vbe *vbe = skl_get_vbe(sdev);
- list_for_each_entry(vbe, &sdev->vbe_list, list) {
- info = vbe_find_substream_info(vbe, substr);
- if (info != NULL)
- return info;
- }
- return NULL;
+ return vbe_find_substream_info(vbe, substr);
}
struct snd_soc_dapm_widget *vbe_skl_find_kcontrol_widget(
@@ -170,12 +174,23 @@ static void vbe_skl_send_or_enqueue(const struct snd_skl_vbe *vbe,
}
}
+void vbe_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
+{
+ struct skl *skl = bus_to_skl(bus);
+ struct snd_skl_vbe *vbe = skl_get_vbe(skl);
+
+ if (hstr->substream)
+ skl_notify_stream_update(bus, hstr->substream);
+
+ vbe->nops.hda_irq_ack(bus, hstr);
+}
+
int vbe_send_kctl_msg(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
struct vfe_kctl_result *result)
{
struct vfe_pending_msg kctl_msg;
- const struct snd_skl_vbe *vbe = get_first_vbe();
+ const struct snd_skl_vbe *vbe = &get_virtio_audio()->vbe;
const struct virtio_vq_info *vq = &vbe->vqs[SKL_VIRTIO_IPC_NOT_RX_VQ];
bool endchain;
@@ -548,6 +563,67 @@ static int vbe_skl_pcm_hw_params(const struct skl *sdev, int vm_id,
return ret;
}
+static int vbe_skl_send_tplg_data(struct snd_skl_vbe *vbe,
+ const struct skl *sdev, const struct firmware *tplg,
+ int vm_id)
+{
+ struct vfe_pending_msg tplg_msg;
+ struct vfe_tplg_data *tplg_data = &tplg_msg.msg.tplg_data;
+ int rem_data = tplg->size, offset;
+ u8 *data_ptr = tplg->data;
+ const struct virtio_vq_info *vq = &vbe->vqs[SKL_VIRTIO_IPC_NOT_RX_VQ];
+
+ tplg_msg.sizeof_msg = sizeof(struct vfe_tplg_data);
+ tplg_data->msg_type = VFE_MSG_TPLG_DATA;
+
+ u32 chunk_length;
+ u8 data[SKL_VIRTIO_TPLG_CHUNK_SIZE];
+
+ for (offset = 0; offset < tplg->size;
+ offset += SKL_VIRTIO_TPLG_CHUNK_SIZE,
+ rem_data -= SKL_VIRTIO_TPLG_CHUNK_SIZE) {
+
+ tplg_data->offset = offset;
+ tplg_data->chunk_size = rem_data > SKL_VIRTIO_TPLG_CHUNK_SIZE ?
+ SKL_VIRTIO_TPLG_CHUNK_SIZE : rem_data;
+ memcpy(tplg_data->data, data_ptr, tplg_data->chunk_size);
+ data_ptr += tplg_data->chunk_size;
+
+ vbe_skl_send_or_enqueue(vbe, vq, &tplg_msg);
+ }
+
+ return 0;
+}
+
+static int vbe_skl_tplg_size(struct snd_skl_vbe *vbe, const struct skl *sdev,
+ int vm_id, const struct vbe_ipc_msg *msg)
+{
+ const struct firmware *tplg;
+ char *tplg_name;
+ int chunks, data, ret;
+ struct vfe_tplg_size *tplg_size = msg->rx_data;
+
+ if (!tplg_size)
+ return -EINVAL;
+
+ //TODO: get tplg file name by guest domain ID
+ tplg_name = "guest_tplg.bin";
+ ret = request_firmware(&tplg, tplg_name, vbe->dev);
+ if (ret < 0)
+ return ret;
+
+ tplg_size->chunk_size = SKL_VIRTIO_TPLG_CHUNK_SIZE;
+ tplg_size->size = tplg->size;
+ tplg_size->chunks = tplg_size->size / SKL_VIRTIO_TPLG_CHUNK_SIZE +
+ tplg_size->size % SKL_VIRTIO_TPLG_CHUNK_SIZE ? 1 : 0;
+
+ vbe_skl_send_tplg_data(vbe, sdev, tplg, vm_id);
+
+ release_firmware(tplg);
+
+ return 0;
+}
+
static int vbe_skl_pcm_trigger(struct skl *sdev, int vm_id,
const struct vbe_substream_info *substr_info,
const struct vbe_ipc_msg *msg)
@@ -608,12 +684,12 @@ static int vbe_skl_kcontrol_check_permission(u32 domain_id,
{
int kcontrol_domain_id;
int ret;
- struct skl *sdev = snd_skl_get_virtio_audio();
+ struct skl *skl = get_virtio_audio()->skl;
- if (sdev == NULL)
+ if (skl == NULL)
return -EINVAL;
- ret = vbe_skl_kcontrol_get_domain_id(sdev, kcontrol,
+ ret = vbe_skl_kcontrol_get_domain_id(skl, kcontrol,
&kcontrol_domain_id);
if (ret < 0)
return ret;
@@ -671,6 +747,23 @@ static int vbe_skl_msg_cfg_handle(struct snd_skl_vbe *vbe,
return 0;
}
+int vbe_skl_msg_tplg_handle(const struct snd_skl_vbe *vbe,
+ const struct skl *sdev, int vm_id, struct vbe_ipc_msg *msg)
+{
+ u32 domain_id = msg->header->domain_id;
+
+ switch (msg->header->cmd) {
+ case VFE_MSG_TPLG_SIZE:
+ return vbe_skl_tplg_size(vbe, sdev, vm_id, msg);
+ default:
+ dev_err(vbe->dev, "Unknown command %d for tplg [%s].\n",
+ msg->header->cmd);
+ break;
+ }
+
+ return 0;
+}
+
static int vbe_skl_msg_pcm_handle(const struct snd_skl_vbe *vbe,
const struct skl *sdev, int vm_id, struct vbe_ipc_msg *msg)
{
@@ -726,6 +819,7 @@ int vbe_skl_msg_kcontrol_handle(const struct snd_skl_vbe *vbe,
return 0;
}
+
static int vbe_skl_not_fwd(const struct snd_skl_vbe *vbe,
const struct skl *sdev, int vm_id, void *ipc_bufs[SKL_VIRTIO_NOT_VQ_SZ],
size_t ipc_lens[SKL_VIRTIO_NOT_VQ_SZ])
@@ -750,7 +844,7 @@ static int vbe_skl_not_fwd(const struct snd_skl_vbe *vbe,
case VFE_MSG_KCTL:
return vbe_skl_msg_kcontrol_handle(vbe, vm_id, &msg);
case VFE_MSG_TPLG:
- //not supported yet
+ return vbe_skl_msg_tplg_handle(vbe, sdev, vm_id, &msg);
break;
case VFE_MSG_CFG:
return vbe_skl_msg_cfg_handle(vbe, sdev, vm_id, &msg);
@@ -942,3 +1036,29 @@ void vbe_skl_handle_kick(const struct snd_skl_vbe *vbe, int vq_idx)
break;
}
}
+
+int vbe_skl_attach(struct snd_skl_vbe *vbe, struct skl *skl)
+{
+ vbe->sdev = skl;
+
+ vbe->nops.hda_irq_ack = skl->skl_sst->hda_irq_ack;
+ skl->skl_sst->hda_irq_ack = vbe_stream_update;
+
+ return 0;
+}
+
+int vbe_skl_detach(struct snd_skl_vbe *vbe, struct skl *skl)
+{
+ if (!vbe->sdev)
+ return 0;
+
+ skl->skl_sst->request_tplg = vbe->nops.request_tplg;
+ skl->skl_sst->hda_irq_ack = vbe->nops.hda_irq_ack;
+
+ /* TODO: Notify FE, close all streams opened by FE and delete all
+ * pending messages
+ */
+
+ vbe->sdev = NULL;
+ return 0;
+}
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-be.h b/sound/soc/intel/skylake/virtio/skl-virtio-be.h
index 93ab96d27281..1a5840f85d72 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-be.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-be.h
@@ -21,13 +21,31 @@
#define SKL_VIRTIO_MSG_TX 1
#define SKL_VIRTIO_MSG_RX 2
+struct skl;
+struct vskl;
struct snd_skl_vbe;
+#define skl_get_vrtdata(skl) \
+ (dev_get_drvdata(&skl->virt_dev->dev))
+#define skl_get_vrtpdata(skl) \
+ ((struct skl_virt_pdata *)(skl_get_vrtdata(skl)))
+#define skl_to_vskl(skl) \
+ ((struct vskl *)(skl_get_vrtpdata(skl)->private_data))
+#define skl_get_vbe(skl) (&(skl_to_vskl(skl))->vbe)
+#define vskl_get_vbe(vskl) (&vskl->vbe)
+
extern int snd_skl_vbe_register(struct skl *sdev, struct snd_skl_vbe **svbe);
extern int snd_skl_vbe_register_client(struct snd_skl_vbe *vbe);
extern void vbe_skl_handle_kick(const struct snd_skl_vbe *vbe, int vq_idx);
-extern struct snd_skl_vbe *get_first_vbe(void);
-extern void *snd_skl_get_virtio_audio(void);
+
+int vbe_skl_attach(struct snd_skl_vbe *vbe, struct skl *skl);
+int vbe_skl_detach(struct snd_skl_vbe *vbe, struct skl *skl);
+struct vskl *get_virtio_audio(void);
+
+struct vskl_native_ops {
+ int (*request_tplg)(struct skl *skl, const struct firmware **fw);
+ void (*hda_irq_ack)(struct hdac_bus *bus, struct hdac_stream *hstr);
+};
struct vbe_substream_info {
struct snd_pcm *pcm;
@@ -38,7 +56,6 @@ struct vbe_substream_info {
struct list_head list;
};
-
struct snd_skl_vbe {
struct skl *sdev;
struct device *dev;
@@ -53,6 +70,8 @@ struct snd_skl_vbe {
struct list_head list;
struct list_head pending_msg_list;
+ struct vskl_native_ops nops;
+
int vmid; /* vm id number */
};
@@ -64,13 +83,14 @@ struct snd_skl_vbe_client {
struct vhm_request *req_buf;
};
-struct virtio_miscdev {
+struct vskl {
struct device *dev;
- int (*open)(struct file *f, void *data);
- long (*ioctl)(struct file *f, void *data, unsigned int ioctl,
- unsigned long arg);
- int (*release)(struct file *f, void *data);
- void *priv;
+ struct snd_skl_vbe vbe;
+
+ struct skl *skl;
};
+void skl_notify_stream_update(struct hdac_bus *bus,
+ struct snd_pcm_substream *substr);
+
#endif
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-common.h b/sound/soc/intel/skylake/virtio/skl-virtio-common.h
index 89e759fc01a0..97cb00e222ca 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-common.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-common.h
@@ -28,6 +28,7 @@
#define SKL_VIRTIO_IPC_REPLY 1
#define SKL_VIRTIO_DOMAIN_NAME_LEN 20
+#define SKL_VIRTIO_TPLG_CHUNK_SIZE 2048
struct vfe_dsp_ipc_msg {
u64 header;
@@ -151,6 +152,19 @@ struct vfe_hw_pos_request {
u64 stream_pos;
};
+struct vfe_tplg_size {
+ u32 chunk_size;
+ u32 chunks;
+ u64 size;
+};
+
+struct vfe_tplg_data {
+ int msg_type;
+ u32 offset;
+ u32 chunk_size;
+ u8 data[SKL_VIRTIO_TPLG_CHUNK_SIZE];
+};
+
struct vfe_kctl_noti {
int msg_type;
struct vfe_kctl_info kcontrol;
@@ -160,6 +174,7 @@ struct vfe_kctl_noti {
union inbox_msg {
struct vfe_hw_pos_request posn;
struct vfe_kctl_noti kctln;
+ struct vfe_tplg_data tplg_data;
};
struct vfe_pending_msg {
@@ -186,6 +201,9 @@ enum vfe_ipc_msg_type {
VFE_MSG_KCTL_SET = VFE_MSG_KCTL | 0x01,
+ VFE_MSG_TPLG_SIZE = VFE_MSG_TPLG | 0x01,
+ VFE_MSG_TPLG_DATA = VFE_MSG_TPLG | 0x02,
+
VFE_MSG_CFG_HDA = VFE_MSG_CFG | 0x01,
VFE_MSG_POS_NOTI = VFE_MSG_POS | 0x01,
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
index b6952cbcaf57..0e4505bd55ca 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
@@ -417,6 +417,28 @@ static void vfe_handle_posn(struct snd_skl_vfe *vfe,
snd_pcm_period_elapsed(substr_info->substream);
}
+static void vfe_handle_tplg(struct snd_skl_vfe *vfe,
+ struct vfe_tplg_data *tplg_data)
+{
+ u8 *data_ptr;
+
+ dev_dbg(&vfe->vdev->dev,
+ "Tplg chunk received offset %d chunk size %d\n",
+ tplg_data->offset, tplg_data->chunk_size);
+
+ mutex_lock(&vfe->tplg.tplg_lock);
+ data_ptr = vfe->tplg.tplg_data.data + tplg_data->offset;
+ memcpy(data_ptr, tplg_data->data, tplg_data->chunk_size);
+ vfe->tplg.data_ready += tplg_data->chunk_size;
+
+ if (vfe->tplg.data_ready >= vfe->tplg.tplg_data.size) {
+ vfe->tplg.load_completed = true;
+ wake_up(&vfe->tplg.waitq);
+ }
+
+ mutex_unlock(&vfe->tplg.tplg_lock);
+}
+
static void vfe_message_loop(struct work_struct *work)
{
struct vfe_inbox_header *header;
@@ -441,10 +463,15 @@ static void vfe_message_loop(struct work_struct *work)
kctl_ipc_handle(0u, &kctln->kcontrol,
&kctln->kcontrol_value, &result);
break;
+ case VFE_MSG_TPLG_DATA:
+ vfe_handle_tplg(vfe,
+ (struct vfe_tplg_data *)header);
+ break;
default:
dev_err(&vfe->vdev->dev,
"Invalid msg Type (%d)\n", header->msg_type);
}
+ vfe_put_inbox_buffer(vfe, header);
}
vfe_put_inbox_buffer(vfe, header);
}
@@ -874,11 +901,65 @@ static struct nhlt_acpi_table *vfe_skl_nhlt_init(struct device *dev)
return nhlt;
}
-
void vfe_skl_pci_dev_release(struct device *dev)
{
}
+static int vfe_request_topology(struct skl *skl, const struct firmware **fw)
+{
+ struct snd_skl_vfe *vfe = get_virtio_audio_fe();
+
+ mutex_lock(&vfe->tplg_init_lock);
+ *fw = &vfe->tplg.tplg_data;
+ mutex_unlock(&vfe->tplg_init_lock);
+
+ return 0;
+}
+
+static int vfe_init_tplg(struct snd_skl_vfe *vfe, struct skl *skl)
+{
+ struct vfe_msg_header msg_header;
+ struct vfe_tplg_size tplg_size;
+ int ret;
+ u8 *tplg_data;
+
+ mutex_init(&vfe->tplg_init_lock);
+ mutex_lock(&vfe->tplg_init_lock);
+
+ mutex_init(&vfe->tplg.tplg_lock);
+ init_waitqueue_head(&vfe->tplg.waitq);
+ vfe->tplg.load_completed = false;
+
+ strcpy(skl->tplg_name, "5a98-INTEL-NHLT-GPA-11-tplg.bin");
+ skl->skl_sst->request_tplg = vfe_request_topology;
+
+ mutex_lock(&vfe->tplg.tplg_lock);
+ msg_header.cmd = VFE_MSG_TPLG_SIZE;
+ ret = vfe_send_msg(vfe, &msg_header,
+ NULL, 0, &tplg_size, sizeof(tplg_size));
+ if (ret < 0)
+ goto error_handl;
+
+ tplg_data = devm_kzalloc(&vfe->vdev->dev,
+ tplg_size.size, GFP_KERNEL);
+ if (!tplg_data) {
+ ret = -ENOMEM;
+ goto error_handl;
+ }
+
+ vfe->tplg.tplg_data.data = tplg_data;
+ vfe->tplg.tplg_data.size = tplg_size.size;
+
+error_handl:
+ mutex_unlock(&vfe->tplg.tplg_lock);
+ if (ret == 0)
+ wait_event(vfe->tplg.waitq, vfe->tplg.load_completed);
+
+ mutex_unlock(&vfe->tplg_init_lock);
+
+ return ret;
+}
+
static int vfe_skl_init(struct virtio_device *vdev)
{
int err;
@@ -914,12 +995,14 @@ static int vfe_skl_init(struct virtio_device *vdev)
if (err < 0)
goto error;
- strcpy(skl->tplg_name, "5a98-INTEL-NHLT-GPA-11-tplg.bin");
-
err = vfe_skl_init_dsp(skl);
if (err < 0)
goto error;
+ err = vfe_init_tplg(vfe, skl);
+ if (err < 0)
+ return err;
+
err = vfe_platform_register(vfe, &vdev->dev);
if (err < 0)
goto error;
@@ -1018,6 +1101,10 @@ 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-fe.h b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
index 18303829c740..ec6cae0c3b89 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
@@ -24,6 +24,15 @@ struct vfe_substream_info {
struct list_head list;
};
+struct vskl_vfe_tplg {
+ struct firmware tplg_data;
+ u64 data_ready;
+
+ struct mutex tplg_lock;
+ wait_queue_head_t waitq;
+ bool load_completed;
+};
+
struct snd_skl_vfe {
struct skl sdev;
struct virtio_device *vdev;
@@ -32,6 +41,10 @@ struct snd_skl_vfe {
void *in_buff[VFE_MSG_BUFF_NUM];
struct kctl_proxy kcon_proxy;
+ struct vskl_vfe_tplg tplg;
+ struct mutex tplg_init_lock;
+
+ struct work_struct init_work;
/* position update work */
struct work_struct posn_update_work;
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-miscdev.c b/sound/soc/intel/skylake/virtio/skl-virtio-miscdev.c
deleted file mode 100644
index a3b4f2f94a91..000000000000
--- a/sound/soc/intel/skylake/virtio/skl-virtio-miscdev.c
+++ /dev/null
@@ -1,463 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// skl-virtio-miscdev.c -- Miscellaneous Virtio device for BE service
-//
-// Copyright (C) 2018 Intel Corporation.
-//
-// Authors: Furtak, Pawel <pawel.furtak@intel.com>
-// Janca, Grzegorz <grzegorz.janca@intel.com>
-//
-// This module registers a device node /dev/vbs_k_audio, that handle
-// the communication between Device Model and the virtio backend service.
-// The device model can control the backend to : set the status,
-// set the vq account and etc. The config of the DM and VBS must be accordance.
-
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-#include "skl-virtio-be.h"
-#include "../skl-sst-ipc.h"
-
-
-static struct virtio_miscdev *virtio_audio;
-static int snd_audio_virtio_miscdev_register(struct device *dev, void *data,
- struct virtio_miscdev **va);
-static int snd_audio_virtio_miscdev_unregister(void);
-
-static struct virtio_miscdev *get_virtio_audio(void)
-{
- return virtio_audio;
-}
-
-void *snd_skl_get_virtio_audio(void)
-{
- struct virtio_miscdev *vaudio = get_virtio_audio();
-
- if (vaudio)
- return vaudio->priv;
-
- return NULL;
-}
-
-struct snd_skl_vbe *get_first_vbe()
-{
- struct skl *sdev = snd_skl_get_virtio_audio();
-
- return list_first_entry_or_null(&sdev->vbe_list,
- struct snd_skl_vbe, list);
-}
-
-struct kctl_proxy *get_kctl_proxy(void)
-{
- struct snd_skl_vbe *vbe = get_first_vbe();
-
- if (vbe != NULL)
- return &vbe->kcon_proxy;
-
- return NULL;
-}
-
-
-
-/* find client from client ID */
-static struct snd_skl_vbe_client *vbe_client_find(struct skl *sdev,
- int client_id)
-{
- struct snd_skl_vbe_client *client;
- struct snd_skl_vbe *vbe;
-
- list_for_each_entry(vbe, &sdev->vbe_list, list) {
- list_for_each_entry(client, &vbe->client_list, list) {
- if (client_id == client->vhm_client_id)
- return client;
- }
- }
-
- return NULL;
-}
-
-static int handle_kick(int client_id, unsigned long *ioreqs_map)
-{
- struct vhm_request *req;
- struct snd_skl_vbe_client *client;
- struct snd_skl_vbe *vbe;
- struct skl *sdev = snd_skl_get_virtio_audio();
- int vcpu, handle;
-
- if (!sdev) {
- pr_err("error: no BE registered for SOF!\n");
- return -EINVAL;
- }
-
- dev_dbg(sdev->skl_sst->dev, "virtio audio kick handling!\n");
-
- /* get the client this notification is for/from? */
- client = vbe_client_find(sdev, client_id);
- if (!client) {
- dev_err(sdev->skl_sst->dev, "Ooops! client %d not found!\n",
- client_id);
- return -EINVAL;
- }
- vbe = client->vbe;
-
- /* go through all vcpu for the valid request buffer */
- while (1) {
- vcpu = find_first_bit(ioreqs_map, client->max_vcpu);
- if (vcpu == client->max_vcpu)
- break;
- req = &client->req_buf[vcpu];
- if (atomic_read(&req->processed) != REQ_STATE_PROCESSING ||
- req->client != client->vhm_client_id)
- continue;
-
- handle = 0;
- dev_dbg(sdev->skl_sst->dev,
- "ioreq type %d, direction %d, addr 0x%llx, size 0x%llx, value 0x%x\n",
- req->type,
- req->reqs.pio_request.direction,
- req->reqs.pio_request.address,
- req->reqs.pio_request.size,
- req->reqs.pio_request.value);
-
- if (req->reqs.pio_request.direction == REQUEST_READ) {
- /*
- * currently we handle kick only,
- * so read will return 0
- */
- req->reqs.pio_request.value = 0;
- } else {
- req->reqs.pio_request.value >= 0 ?
- (handle = 1) : (handle = 0);
- }
-
- acrn_ioreq_complete_request(client->vhm_client_id, vcpu, req);
-
- /* handle VQ kick if needed */
- if (handle)
- vbe_skl_handle_kick(vbe, req->reqs.pio_request.value);
- }
-
- return 0;
-}
-
-int snd_skl_virtio_register_vbe(struct skl *sdev, struct snd_skl_vbe **svbe)
-{
- struct snd_skl_vbe *vbe;
- struct virtio_vq_info *vqs;
- struct device *dev = &sdev->pci->dev;
- int i;
-
- vbe = devm_kzalloc(dev, sizeof(*vbe), GFP_KERNEL);
- if (!vbe)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&vbe->client_list);
- INIT_LIST_HEAD(&vbe->substr_info_list);
- INIT_LIST_HEAD(&vbe->pending_msg_list);
- spin_lock_init(&vbe->posn_lock);
- vbe->sdev = sdev;
- vbe->dev = dev;
-
- vqs = vbe->vqs;
- for (i = 0; i < SKL_VIRTIO_NUM_OF_VQS; i++) {
- vqs[i].dev = &vbe->dev_info;
- /*
- * currently relies on VHM to kick us,
- * thus vq_notify not used
- */
- vqs[i].vq_notify = NULL;
- }
-
- /* link dev and vqs */
- vbe->dev_info.vqs = vqs;
-
- virtio_dev_init(&vbe->dev_info, vqs, SKL_VIRTIO_NUM_OF_VQS);
-
- *svbe = vbe;
-
- return 0;
-}
-
-/*
- * register vhm client with virtio.
- * vhm use the client to handle the io access from FE
- */
-int snd_skl_virtio_register_client(struct snd_skl_vbe *vbe)
-{
- struct virtio_dev_info *dev_info = &vbe->dev_info;
- struct vm_info info;
- struct snd_skl_vbe_client *client;
- unsigned int vmid;
- int ret;
-
- /*
- * vbs core has mechanism to manage the client
- * there is no need to handle this in the special BE driver
- * let's use the vbs core client management later
- */
- client = devm_kzalloc(vbe->dev, sizeof(*client), GFP_KERNEL);
- if (!client)
- return -EINVAL;
- client->vbe = vbe;
-
- vmid = dev_info->_ctx.vmid;
- client->vhm_client_id = acrn_ioreq_create_client(vmid, handle_kick,
- "snd_skl_vbe kick init\n");
- if (client->vhm_client_id < 0) {
- dev_err(vbe->dev, "failed to create client of acrn ioreq!\n");
- return client->vhm_client_id;
- }
-
- ret = acrn_ioreq_add_iorange(client->vhm_client_id, REQ_PORTIO,
- dev_info->io_range_start,
- dev_info->io_range_start +
- dev_info->io_range_len - 1);
- if (ret < 0) {
- dev_err(vbe->dev, "failed to add iorange to acrn ioreq!\n");
- goto err;
- }
-
- /*
- * setup the vm information, such as max_vcpu and max_gfn
- * BE need this information to handle the vqs
- */
- ret = vhm_get_vm_info(vmid, &info);
- if (ret < 0) {
- dev_err(vbe->dev, "failed in vhm_get_vm_info!\n");
- goto err;
- }
- client->max_vcpu = info.max_vcpu;
-
- /* TODO: comment what this is doing */
- client->req_buf = acrn_ioreq_get_reqbuf(client->vhm_client_id);
- if (!client->req_buf) {
- dev_err(vbe->dev, "failed in acrn_ioreq_get_reqbuf!\n");
- goto err;
- }
-
- /* just attach once as vhm will kick kthread */
- acrn_ioreq_attach_client(client->vhm_client_id, 0);
-
- /* complete client init and add to list */
- list_add(&client->list, &vbe->client_list);
-
- return 0;
-err:
- acrn_ioreq_destroy_client(client->vhm_client_id);
- return -EINVAL;
-}
-
-static int snd_skl_virtio_open(struct file *f, void *data)
-{
- struct skl *sdev = (struct skl *)data;
- struct snd_skl_vbe *vbe;
- int ret;
-
- ret = snd_skl_virtio_register_vbe(sdev, &vbe);
- if (ret)
- return ret;
-
- /*
- * link to sdev->vbe_list
- * Maybe virtio_miscdev managing the list is more reasonable.
- * Let's use sdev to manage the FE audios now.
- */
- list_add(&vbe->list, &sdev->vbe_list);
- f->private_data = vbe;
-
- return 0;
-}
-
-static long snd_skl_virtio_ioctl(struct file *f, void *data, unsigned int ioctl,
- unsigned long arg)
-{
- struct snd_skl_vbe *vbe = f->private_data;
- void __user *argp = (void __user *)arg;
- int ret;
-
- switch (ioctl) {
- case VBS_SET_DEV:
- ret = virtio_dev_ioctl(&vbe->dev_info, ioctl, argp);
- if (!ret)
- vbe->vmid = vbe->dev_info._ctx.vmid;
- break;
- case VBS_SET_VQ:
- ret = virtio_vqs_ioctl(&vbe->dev_info, ioctl, argp);
- if (ret)
- return ret;
-
- ret = snd_skl_virtio_register_client(vbe);
- if (ret)
- return ret;
- /*
- * TODO: load tplg and send to FE here
- *
- * The better method is FE driver send FE-tplg id
- * and request FE-tplg.
- * Then BE loads the corresponding tplg based on
- * the FE-tplg id and send to FE driver.
- */
- break;
- default:
- pr_err("%s: _snd_virtio_miscdevice Unsupported ioctl cmd[%d].\n",
- __func__, ioctl);
- return -ENOIOCTLCMD;
- }
-
- return ret;
-}
-
-static int snd_skl_virtio_release(struct file *f, void *data)
-{
- struct snd_skl_vbe *vbe = f->private_data;
-
- list_del(&vbe->list);
- devm_kfree(vbe->sdev->skl_sst->dev, vbe);
- f->private_data = NULL;
-
- return 0;
-}
-
-/**
- * snd_soc_skl_virtio_miscdev_register() - init the virtio be audio driver
- * @sdev: the skl structure
- *
- * This function registers the misc device, which will be used
- * by the user space to communicate with the audio driver.
- *
- * Return: 0 for success or negative value for err
- */
-int snd_soc_skl_virtio_miscdev_register(struct skl *sdev)
-{
- struct virtio_miscdev *vaudio;
- int ret;
-
- ret = snd_audio_virtio_miscdev_register(sdev->skl_sst->dev,
- sdev, &vaudio);
- if (ret) {
- dev_err(vaudio->dev, "failed to register misc device %d\n",
- ret);
- return ret;
- }
-
- INIT_LIST_HEAD(&sdev->vbe_list);
-
- vaudio->open = snd_skl_virtio_open;
- vaudio->ioctl = snd_skl_virtio_ioctl;
- vaudio->release = snd_skl_virtio_release;
-
- dev_info(vaudio->dev, "register misc device success\n");
- return 0;
-}
-EXPORT_SYMBOL(snd_soc_skl_virtio_miscdev_register);
-
-/**
- * snd_soc_skl_virtio_miscdev_unregister() - release the virtio be audio driver
- *
- * This function deregisters the misc device, and free virtio_miscdev
- *
- */
-int snd_soc_skl_virtio_miscdev_unregister(void)
-{
- return snd_audio_virtio_miscdev_unregister();
-}
-EXPORT_SYMBOL(snd_soc_skl_virtio_miscdev_unregister);
-
-static int vbs_audio_open(struct inode *inode, struct file *f)
-{
- struct virtio_miscdev *vaudio = get_virtio_audio();
-
- if (!vaudio)
- return -ENODEV; /* This should never happen */
-
- dev_dbg(vaudio->dev, "virtio audio open\n");
- if (vaudio->open)
- return vaudio->open(f, virtio_audio->priv);
-
- return 0;
-}
-
-static long vbs_audio_ioctl(struct file *f, unsigned int ioctl,
- unsigned long arg)
-{
- struct virtio_miscdev *vaudio = get_virtio_audio();
-
- if (!vaudio)
- return -ENODEV; /* This should never happen */
-
- dev_dbg(vaudio->dev, "virtio audio ioctl\n");
- if (vaudio->ioctl)
- return vaudio->ioctl(f, vaudio->priv, ioctl, arg);
- else
- return -ENXIO;
-}
-
-static int vbs_audio_release(struct inode *inode, struct file *f)
-{
- struct virtio_miscdev *vaudio = get_virtio_audio();
-
- if (!vaudio)
- return -ENODEV; /* This should never happen */
-
- dev_dbg(vaudio->dev, "release virtio audio\n");
-
- if (vaudio->release)
- vaudio->release(f, vaudio->priv);
-
- return 0;
-}
-
-static const struct file_operations vbs_audio_fops = {
- .owner = THIS_MODULE,
- .release = vbs_audio_release,
- .unlocked_ioctl = vbs_audio_ioctl,
- .open = vbs_audio_open,
- .llseek = noop_llseek,
-};
-
-static struct miscdevice vbs_audio_k = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "vbs_k_audio",
- .fops = &vbs_audio_fops,
-};
-
-static int snd_audio_virtio_miscdev_register(struct device *dev, void *data,
- struct virtio_miscdev **va)
-{
- struct virtio_miscdev *vaudio;
- int ret;
-
- ret = misc_register(&vbs_audio_k);
- if (ret) {
- dev_err(dev, "misc device register failed %d\n", ret);
- return ret;
- }
-
- vaudio = kzalloc(sizeof(*vaudio), GFP_KERNEL);
- if (!vaudio) {
- misc_deregister(&vbs_audio_k);
- return -ENOMEM;
- }
-
- vaudio->priv = data;
- vaudio->dev = dev;
- virtio_audio = vaudio;
- *va = vaudio;
-
- return 0;
-}
-
-static int snd_audio_virtio_miscdev_unregister(void)
-{
- if (virtio_audio) {
- misc_deregister(&vbs_audio_k);
- kfree(virtio_audio);
- virtio_audio = NULL;
- }
-
- return 0;
-}
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio.h b/sound/soc/intel/skylake/virtio/skl-virtio.h
index 1a37ae599b85..390d31885437 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio.h
@@ -10,18 +10,6 @@
#ifndef __SOUND_SOC_SKL_VIRTIO_H
#define __SOUND_SOC_SKL_VIRTIO_H
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_BE)
-
-extern int snd_soc_skl_virtio_miscdev_register(struct skl *sdev);
-extern void skl_notify_stream_update(struct hdac_bus *bus,
- struct snd_pcm_substream *substr);
-#else
-
-#define snd_soc_skl_virtio_miscdev_register(...) {}
-#define skl_notify_stream_update(...) {}
-
-#endif
-
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_VIRTIO_FE)
extern int vfe_sst_dsp_init(struct device *dev, void __iomem *mmio_base,
--
https://clearlinux.org