Skip to content

Commit

Permalink
ASoC: SOF: add sof vBE and vFE support
Browse files Browse the repository at this point in the history
This patch adds the sof virtio BE and FE support.
It will create a dev node for the communication to the userspace.

It also handles the virtio vq event. It dispatches the different
vq kicks to different handlers. In the virtio vq handling, it handles
all the ipc events from vFE.

When there is position update from FW, it will check whether there is
an available entry in notification vq. If yes, send the position update
notification immediately. If there is no available entry, add the position
update event in a list. As soon as the notification vq has an available
entry, send the position update to the vFE.

For vFE, it will create a virtual audio device driver and communite with
vBE audio driver to create PCMs and playback/capture streams.

Signed-off-by: Libin Yang <libin.yang@intel.com>
  • Loading branch information
libinyang authored and lgirdwood committed Oct 18, 2018
1 parent 4a0e72f commit 481973c
Show file tree
Hide file tree
Showing 14 changed files with 2,000 additions and 128 deletions.
4 changes: 4 additions & 0 deletions include/sound/sof.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <uapi/sound/sof-ipc.h>

struct snd_sof_dsp_ops;
struct virtio_device;

/* SOF probe type */
enum sof_device_type {
Expand Down Expand Up @@ -53,6 +54,9 @@ struct snd_sof_pdata {
struct device *dev;
enum sof_device_type type;

struct sof_vfe *vfe;
int is_vfe;

/* descriptor */
const struct sof_dev_desc *desc;

Expand Down
42 changes: 42 additions & 0 deletions include/uapi/sound/sof-virtio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
*
* Contact Information:
* Author: Luo Xionghu <xionghu.luo@intel.com>
* Liam Girdwood <liam.r.girdwood@linux.intel.com>.
*/

#ifndef _SOF_VIRTIO_H
#define _SOF_VIRTIO_H

/* Currently we defined 4 vqs to do the IPC, CMD_TX is for send the msg
* from FE to BE, and CMD_RX is to receive the reply. NOT_RX is to receive
* the notification, and NOT_TX is to send empty buffer from FE to BE.
* If we can handle the IPC with only 2 vqs, the config still need to
* be changed in the device model(VM config), then only CMD_VQ and NOT_VQ
* is needed.
*/

#define SOF_VIRTIO_IPC_CMD_TX_VQ 0
#define SOF_VIRTIO_IPC_CMD_RX_VQ 1
#define SOF_VIRTIO_IPC_NOT_TX_VQ 2
#define SOF_VIRTIO_IPC_NOT_RX_VQ 3
#define SOF_VIRTIO_NUM_OF_VQS 4

/* command messages from FE to BE, trigger/open/hw_params and so on */
#define SOF_VIRTIO_IPC_CMD_TX_VQ_NAME "sof-ipc-cmd-tx"

/* get the reply of the command message */
#define SOF_VIRTIO_IPC_CMD_RX_VQ_NAME "sof-ipc-cmd-rx"

/* first the FE need send empty buffer to BE to get the notification */
#define SOF_VIRTIO_IPC_NOT_TX_VQ_NAME "sof-ipc-not-tx"

/* the vq to get the notification */
#define SOF_VIRTIO_IPC_NOT_RX_VQ_NAME "sof-ipc-not-rx"

#endif
12 changes: 12 additions & 0 deletions sound/soc/intel/boards/bxt_tdf8532.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = {
.dpcm_playback = 1,
.no_pcm = 1,
},
{
/* SSP4 for vm */
.name = "vm_dai_link",
.id = 6,
.cpu_dai_name = "SSP4 Pin",
.codec_name = "i2c-INT34C3:00",
.codec_dai_name = "tdf8532-hifi",
.platform_name = "0000:00:0e.0",
.ignore_suspend = 1,
.dpcm_playback = 1,
.no_pcm = 1,
},
};

#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL)
Expand Down
10 changes: 10 additions & 0 deletions sound/soc/sof/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ ccflags-y += -DDEBUG

snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o compressed.o utils.o

ifdef CONFIG_SND_SOC_SOF_VIRTIO_BE
snd-sof-objs += virtio-be.o virtio-miscdev.o
endif

ifdef CONFIG_SND_SOC_SOF_VIRTIO_FE
snd-virtio-fe-objs += virtio-fe.o
endif

snd-sof-spi-objs := hw-spi.o

snd-sof-pci-objs := sof-pci-dev.o
Expand All @@ -16,6 +25,7 @@ obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o
obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o
obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o
obj-$(CONFIG_SND_SOC_SOF_SPI) += sof-spi-dev.o
obj-$(CONFIG_SND_SOC_SOF_VIRTIO_FE) += virtio-fe.o

obj-$(CONFIG_SND_SOC_SOF_SPIDSP) += snd-sof-spi.o

Expand Down
33 changes: 33 additions & 0 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,

return NULL;
}
EXPORT_SYMBOL(snd_sof_find_spcm_comp);

struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
unsigned int pcm_id)
Expand Down Expand Up @@ -224,6 +225,25 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev,
return pages;
}

static void sof_virtio_vfe_init(struct snd_sof_dev *sdev,
struct snd_sof_pdata *plat_data)
{
sdev->is_vfe = plat_data->is_vfe;

/*
* Currently we only support one VM. comp_id from 0 to
* SOF_VIRTIO_MAX_GOS_COMPS - 1 is for SOS. Other comp_id numbers
* are for VM1.
* TBD: comp_id number range should be dynamically assigned when
* multiple VMs are supported.
*/
if (sdev->is_vfe) {
sdev->next_comp_id = SOF_VIRTIO_MAX_GOS_COMPS;
sdev->vfe = plat_data->vfe;
sdev->vfe->sdev = sdev;
}
}

/*
* SOF Driver enumeration.
*/
Expand Down Expand Up @@ -256,6 +276,7 @@ static int sof_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&sdev->widget_list);
INIT_LIST_HEAD(&sdev->dai_list);
INIT_LIST_HEAD(&sdev->route_list);
INIT_LIST_HEAD(&sdev->vbe_list);
dev_set_drvdata(&pdev->dev, sdev);
spin_lock_init(&sdev->ipc_lock);
spin_lock_init(&sdev->hw_lock);
Expand Down Expand Up @@ -288,13 +309,22 @@ static int sof_probe(struct platform_device *pdev)
goto dbg_err;
}

/* optionally register virtio miscdev */
sof_virtio_miscdev_register(sdev);

/* init the IPC */
sdev->ipc = snd_sof_ipc_init(sdev);
if (!sdev->ipc) {
dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
goto ipc_err;
}

sof_virtio_vfe_init(sdev, plat_data);

/* vFE will not touch HW. Let's skip fw loading */
if (sdev->is_vfe)
goto skip_load_fw_and_trace;

/* load the firmware */
ret = snd_sof_load_firmware(sdev, true);
if (ret < 0) {
Expand All @@ -319,6 +349,8 @@ static int sof_probe(struct platform_device *pdev)
"warning: failed to initialize trace %d\n", ret);
}

skip_load_fw_and_trace:

/* now register audio DSP platform driver and dai */
ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv,
sdev->ops->drv,
Expand Down Expand Up @@ -383,6 +415,7 @@ static int sof_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
snd_sof_fw_unload(sdev);
snd_sof_ipc_free(sdev);
sof_virtio_miscdev_unregister();
snd_sof_free_debug(sdev);
snd_sof_release_trace(sdev);
snd_sof_remove(sdev);
Expand Down
3 changes: 3 additions & 0 deletions sound/soc/sof/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)

memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn));

/* optionally update position for vBE */
sof_vbe_update_guest_posn(sdev, &posn);

/* only inform ALSA for period_wakeup mode */
if (!spcm->stream[direction].substream->runtime->no_period_wakeup)
snd_pcm_period_elapsed(spcm->stream[direction].substream);
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ static int sof_pcm_probe(struct snd_soc_component *component)

/* load the default topology */
sdev->component = component;
sdev->card = component->card;

switch (plat_data->type) {
case SOF_DEVICE_SPI:
Expand Down
94 changes: 94 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <uapi/sound/sof-ipc.h>
#include <uapi/sound/sof-fw.h>
#include <uapi/sound/asoc.h>
#include <uapi/sound/sof-virtio.h>
#include <sound/hdaudio.h>
#include <sound/compress_driver.h>

Expand Down Expand Up @@ -54,6 +55,11 @@
#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)

/* The maximum number of components a virtio guest vFE driver can use */
#define SOF_VIRTIO_MAX_GOS_COMPS 1000

#define SOF_VIRTIO_COMP_ID_UNASSIGNED 0xffffffff

struct snd_sof_dev;
struct snd_sof_ipc_msg;
struct snd_sof_ipc;
Expand All @@ -62,6 +68,8 @@ struct snd_soc_tplg_ops;
struct snd_soc_component;
struct sof_intel_hda_dev;
struct snd_sof_pdata;
struct virtio_device;
struct virtqueue;

/*
* SOF DSP HW abstraction operations.
Expand Down Expand Up @@ -290,6 +298,47 @@ struct snd_sof_dai {
struct list_head list; /* list in sdev dai list */
};

/*
* in virtio iovec array:
* iovec[0]: the ipc message data between vFE and vBE
* iovec[1]: the ipc reply data between vFE and vBE
*/
#define SOF_VIRTIO_IPC_MSG 0
#define SOF_VIRTIO_IPC_REPLY 1

/* Virtio Frontend */
struct sof_vfe {
struct sof_virtio_priv *priv;
struct snd_sof_dev *sdev;

/* IPC cmd from frontend to backend */
struct virtqueue *ipc_cmd_tx_vq;

/* IPC cmd reply from backend to frontend */
struct virtqueue *ipc_cmd_rx_vq;

/* IPC notification from backend to frontend */
struct virtqueue *ipc_not_rx_vq;

/* IPC notification reply from frontend to backend */
struct virtqueue *ipc_not_tx_vq;

/* position update work */
struct work_struct posn_update_work;

/* current pending cmd message */
struct snd_sof_ipc_msg *msg;

/* current and pending notification */
struct snd_sof_ipc_msg *not;
struct sof_ipc_stream_posn *posn;
};

struct vbs_sof_posn {
struct list_head list;
struct sof_ipc_stream_posn pos;
};

/*
* SOF Device Level.
*/
Expand All @@ -302,6 +351,7 @@ struct snd_sof_dev {

/* ASoC components */
struct snd_soc_component_driver plat_drv;
struct snd_soc_card *card;

/* DSP firmware boot */
wait_queue_head_t boot_wait;
Expand Down Expand Up @@ -358,6 +408,11 @@ struct snd_sof_dev {
wait_queue_head_t waitq;
int code_loading;

/* virtio for BE and FE */
struct list_head vbe_list;
struct sof_vfe *vfe;
int is_vfe;

/* DMA for Trace */
struct snd_dma_buffer dmatb;
struct snd_dma_buffer dmatp;
Expand All @@ -377,6 +432,29 @@ struct snd_sof_dev {
#define sof_to_bus(s) (&(s)->hda->hbus.core)
#define sof_to_hbus(s) (&(s)->hda->hbus)

#if IS_ENABLED(CONFIG_SND_SOC_SOF_VIRTIO_BE)
int sof_virtio_miscdev_register(struct snd_sof_dev *sdev);
int sof_virtio_miscdev_unregister(void);
int sof_vbe_update_guest_posn(struct snd_sof_dev *sdev,
struct sof_ipc_stream_posn *posn);
#else
static inline int sof_virtio_miscdev_register(struct snd_sof_dev *sdev)
{
return 0;
}

static inline int sof_virtio_miscdev_unregister(void)
{
return 0;
}

static inline int sof_vbe_update_guest_posn(struct snd_sof_dev *sdev,
struct sof_ipc_stream_posn *posn)
{
return 0;
}
#endif

/*
* SOF platform private struct used as drvdata of
* platform dev (e.g. pci/acpi/spi...) drvdata.
Expand Down Expand Up @@ -494,10 +572,26 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
void *stack, size_t stack_size);
int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev);

/*
* VirtIO
*/
int sof_virtio_submit_guest_ipc(struct snd_sof_dev *sdev, int vm_id,
void *ipc_buf, void *reply_buf,
size_t count, size_t reply_sz);
int snd_sof_virtio_fs_init(struct snd_sof_dev *sdev);
int snd_sof_virtio_fs_release(void);
int sof_virtio_update_guest_posn(void *ctx, struct sof_ipc_stream_posn *posn);
int sof_virtio_try_update_guest_posn(struct snd_sof_dev *sdev,
struct sof_ipc_stream_posn *posn);
void sof_virtio_set_spcm_posn_offset(struct snd_sof_pcm *spcm, int direction);
int sof_virtio_register_guest(void *ctx);
int sof_virtio_release_guest(int id);

/*
* Platform specific ops.
*/
extern struct snd_compr_ops sof_compressed_ops;
extern struct snd_sof_dsp_ops snd_sof_virtio_fe_ops;

/*
* Kcontrols.
Expand Down
Loading

0 comments on commit 481973c

Please sign in to comment.