meta-agl-bsp: update virtio-aarch64 65/27465/2
authorScott Murray <scott.murray@konsulko.com>
Mon, 9 May 2022 21:53:46 +0000 (17:53 -0400)
committerScott Murray <scott.murray@konsulko.com>
Tue, 10 May 2022 10:19:22 +0000 (10:19 +0000)
Updates to get the virtio-aarch64 machine building after the
upgrade to Yocto Project 4.0 / kirkstone:
- Switch to the 5.15 linux-yocto kernel and drop the local backport
  of the 5.10 recipe.
- Fix override syntax in the machine-specific linux-yocto bbappend.
- Remove all the patches applied for the virtio and virtio-snd
  configuration fragments, they seem to have all been applied
  upstream.

Bug-AGL: SPEC-4356

Signed-off-by: Scott Murray <scott.murray@konsulko.com>
Change-Id: I96d4bb9b04d74280d1a3767fe17284fe6049fcba
Reviewed-on: https://gerrit.automotivelinux.org/gerrit/c/AGL/meta-agl/+/27465
Reviewed-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
Tested-by: Jenkins Job builder account
ci-image-build: Jenkins Job builder account
ci-image-boot-test: Jenkins Job builder account

15 files changed:
meta-agl-bsp/conf/machine/include/virtio.inc
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-input-add-multi-touch-support.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0001-uapi-virtio_ids-add-a-sound-device-type-ID-from-OASI.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0002-ALSA-virtio-add-virtio-sound-driver.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0003-ALSA-virtio-handling-control-messages.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0004-ALSA-virtio-build-PCM-devices-and-substream-hardware.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0005-ALSA-virtio-handling-control-and-I-O-messages-for-th.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0006-ALSA-virtio-PCM-substream-operators.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0007-ALSA-virtio-introduce-jack-support.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0009-ALSA-virtio-introduce-device-suspend-resume-support.patch [deleted file]
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/virtio-snd.scc
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio.scc
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto_%.bbappend
meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto_5.10.bb [deleted file]

index 8ee71a8..6f8a638 100644 (file)
@@ -16,19 +16,8 @@ RDEPENDS:${KERNEL_PACKAGE_NAME}-base = ""
 PREFERRED_PROVIDER_virtual/kernel ??= "linux-yocto"
 
 # Use newer kernel
-PREFERRED_VERSION_linux-yocto = "5.10.%"
-
-# Clear since it is set to 'sllin' in packagegroup-agl-demo.bb, and sllin is not
-# compatible with kernel 5.10 at the moment.
-LIN_DRIVERS = ""
-
-# Clear since it is set to 'lttng-modules' in packagegroup-core-tools-profile.bb,
-# and lttng-modules are not compatible with 5.10 kernel used for virtio.
-LTTNGMODULES:virtio-all = ""
+PREFERRED_VERSION_linux-yocto = "5.15.%"
 
 EXTRA_IMAGEDEPENDS += "qemu-native qemu-helper-native"
 
 IMAGE_CLASSES += "qemuboot"
-
-# most driver fails to compile
-MOST_DRIVERS ?= ""
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-input-add-multi-touch-support.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-input-add-multi-touch-support.patch
deleted file mode 100644 (file)
index 59a9f9b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-From 16c10bede8b3d8594279752bf53153491f3f944f Mon Sep 17 00:00:00 2001
-From: Mathias Crombez <mathias.crombez@faurecia.com>
-Date: Fri, 15 Jan 2021 02:26:23 +0200
-Subject: [PATCH] virtio-input: add multi-touch support
-
-Without multi-touch slots allocated, ABS_MT_SLOT events will be lost by
-input_handle_abs_event.
-
-Implementation is based on uinput_create_device.
-
-Signed-off-by: Mathias Crombez <mathias.crombez@faurecia.com>
-Co-developed-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
-Link: https://lore.kernel.org/r/20210115002623.8576-1-vasyl.vavrychuk@opensynergy.com
-Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
----
- drivers/virtio/virtio_input.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
-index 244965c20d9b..ce51ae165943 100644
---- a/drivers/virtio/virtio_input.c
-+++ b/drivers/virtio/virtio_input.c
-@@ -7,6 +7,7 @@
- #include <uapi/linux/virtio_ids.h>
- #include <uapi/linux/virtio_input.h>
-+#include <linux/input/mt.h>
- struct virtio_input {
-       struct virtio_device       *vdev;
-@@ -219,7 +220,7 @@ static int virtinput_probe(struct virtio_device *vdev)
-       struct virtio_input *vi;
-       unsigned long flags;
-       size_t size;
--      int abs, err;
-+      int abs, err, nslots;
-       if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
-               return -ENODEV;
-@@ -304,6 +305,13 @@ static int virtinput_probe(struct virtio_device *vdev)
-                               continue;
-                       virtinput_cfg_abs(vi, abs);
-               }
-+
-+              if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {
-+                      nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;
-+                      err = input_mt_init_slots(vi->idev, nslots, 0);
-+                      if (err)
-+                              goto err_mt_init_slots;
-+              }
-       }
-       virtio_device_ready(vdev);
-@@ -319,6 +327,7 @@ static int virtinput_probe(struct virtio_device *vdev)
-       spin_lock_irqsave(&vi->lock, flags);
-       vi->ready = false;
-       spin_unlock_irqrestore(&vi->lock, flags);
-+err_mt_init_slots:
-       input_free_device(vi->idev);
- err_input_alloc:
-       vdev->config->del_vqs(vdev);
--- 
-2.31.1
-
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0001-uapi-virtio_ids-add-a-sound-device-type-ID-from-OASI.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0001-uapi-virtio_ids-add-a-sound-device-type-ID-from-OASI.patch
deleted file mode 100644 (file)
index e303d10..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From 6afbb3650d7e02785030f1212c88b50d7296bb45 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:01 +0100
-Subject: [PATCH] uapi: virtio_ids: add a sound device type ID from OASIS spec
-
-The OASIS virtio spec defines a sound device type ID that is not
-present in the header yet.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-2-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- include/uapi/linux/virtio_ids.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
-index b052355ac7a3..bc740d6d2259 100644
---- a/include/uapi/linux/virtio_ids.h
-+++ b/include/uapi/linux/virtio_ids.h
-@@ -45,6 +45,7 @@
- #define VIRTIO_ID_CRYPTO       20 /* virtio crypto */
- #define VIRTIO_ID_IOMMU        23 /* virtio IOMMU */
- #define VIRTIO_ID_MEM          24 /* virtio mem */
-+#define VIRTIO_ID_SOUND        25 /* virtio sound */
- #define VIRTIO_ID_FS           26 /* virtio filesystem */
- #define VIRTIO_ID_PMEM         27 /* virtio pmem */
- #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0002-ALSA-virtio-add-virtio-sound-driver.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0002-ALSA-virtio-add-virtio-sound-driver.patch
deleted file mode 100644 (file)
index e2f8044..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-From a1cde5ccba57562aa77739b63b50586e6b197b52 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:02 +0100
-Subject: [PATCH] ALSA: virtio: add virtio sound driver
-
-Introduce skeleton of the virtio sound driver. The driver implements
-the virtio sound device specification, which has become part of the
-virtio standard.
-
-Initial initialization of the device, virtqueues and creation of an
-empty ALSA sound device.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-3-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- MAINTAINERS                     |   9 +
- include/uapi/linux/virtio_snd.h | 334 ++++++++++++++++++++++++++++++++
- sound/Kconfig                   |   2 +
- sound/Makefile                  |   3 +-
- sound/virtio/Kconfig            |  10 +
- sound/virtio/Makefile           |   7 +
- sound/virtio/virtio_card.c      | 324 +++++++++++++++++++++++++++++++
- sound/virtio/virtio_card.h      |  65 +++++++
- 8 files changed, 753 insertions(+), 1 deletion(-)
- create mode 100644 include/uapi/linux/virtio_snd.h
- create mode 100644 sound/virtio/Kconfig
- create mode 100644 sound/virtio/Makefile
- create mode 100644 sound/virtio/virtio_card.c
- create mode 100644 sound/virtio/virtio_card.h
-
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 407ae5c24566..49772b741967 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -18670,6 +18670,15 @@ W:    https://virtio-mem.gitlab.io/
- F:    drivers/virtio/virtio_mem.c
- F:    include/uapi/linux/virtio_mem.h
-+VIRTIO SOUND DRIVER
-+M:    Anton Yakovlev <anton.yakovlev@opensynergy.com>
-+M:    "Michael S. Tsirkin" <mst@redhat.com>
-+L:    virtualization@lists.linux-foundation.org
-+L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
-+S:    Maintained
-+F:    include/uapi/linux/virtio_snd.h
-+F:    sound/virtio/*
-+
- VIRTUAL BOX GUEST DEVICE DRIVER
- M:    Hans de Goede <hdegoede@redhat.com>
- M:    Arnd Bergmann <arnd@arndb.de>
-diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
-new file mode 100644
-index 000000000000..dfe49547a7b0
---- /dev/null
-+++ b/include/uapi/linux/virtio_snd.h
-@@ -0,0 +1,334 @@
-+/* SPDX-License-Identifier: BSD-3-Clause */
-+/*
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#ifndef VIRTIO_SND_IF_H
-+#define VIRTIO_SND_IF_H
-+
-+#include <linux/virtio_types.h>
-+
-+/*******************************************************************************
-+ * CONFIGURATION SPACE
-+ */
-+struct virtio_snd_config {
-+      /* # of available physical jacks */
-+      __le32 jacks;
-+      /* # of available PCM streams */
-+      __le32 streams;
-+      /* # of available channel maps */
-+      __le32 chmaps;
-+};
-+
-+enum {
-+      /* device virtqueue indexes */
-+      VIRTIO_SND_VQ_CONTROL = 0,
-+      VIRTIO_SND_VQ_EVENT,
-+      VIRTIO_SND_VQ_TX,
-+      VIRTIO_SND_VQ_RX,
-+      /* # of device virtqueues */
-+      VIRTIO_SND_VQ_MAX
-+};
-+
-+/*******************************************************************************
-+ * COMMON DEFINITIONS
-+ */
-+
-+/* supported dataflow directions */
-+enum {
-+      VIRTIO_SND_D_OUTPUT = 0,
-+      VIRTIO_SND_D_INPUT
-+};
-+
-+enum {
-+      /* jack control request types */
-+      VIRTIO_SND_R_JACK_INFO = 1,
-+      VIRTIO_SND_R_JACK_REMAP,
-+
-+      /* PCM control request types */
-+      VIRTIO_SND_R_PCM_INFO = 0x0100,
-+      VIRTIO_SND_R_PCM_SET_PARAMS,
-+      VIRTIO_SND_R_PCM_PREPARE,
-+      VIRTIO_SND_R_PCM_RELEASE,
-+      VIRTIO_SND_R_PCM_START,
-+      VIRTIO_SND_R_PCM_STOP,
-+
-+      /* channel map control request types */
-+      VIRTIO_SND_R_CHMAP_INFO = 0x0200,
-+
-+      /* jack event types */
-+      VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
-+      VIRTIO_SND_EVT_JACK_DISCONNECTED,
-+
-+      /* PCM event types */
-+      VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
-+      VIRTIO_SND_EVT_PCM_XRUN,
-+
-+      /* common status codes */
-+      VIRTIO_SND_S_OK = 0x8000,
-+      VIRTIO_SND_S_BAD_MSG,
-+      VIRTIO_SND_S_NOT_SUPP,
-+      VIRTIO_SND_S_IO_ERR
-+};
-+
-+/* common header */
-+struct virtio_snd_hdr {
-+      __le32 code;
-+};
-+
-+/* event notification */
-+struct virtio_snd_event {
-+      /* VIRTIO_SND_EVT_XXX */
-+      struct virtio_snd_hdr hdr;
-+      /* optional event data */
-+      __le32 data;
-+};
-+
-+/* common control request to query an item information */
-+struct virtio_snd_query_info {
-+      /* VIRTIO_SND_R_XXX_INFO */
-+      struct virtio_snd_hdr hdr;
-+      /* item start identifier */
-+      __le32 start_id;
-+      /* item count to query */
-+      __le32 count;
-+      /* item information size in bytes */
-+      __le32 size;
-+};
-+
-+/* common item information header */
-+struct virtio_snd_info {
-+      /* function group node id (High Definition Audio Specification 7.1.2) */
-+      __le32 hda_fn_nid;
-+};
-+
-+/*******************************************************************************
-+ * JACK CONTROL MESSAGES
-+ */
-+struct virtio_snd_jack_hdr {
-+      /* VIRTIO_SND_R_JACK_XXX */
-+      struct virtio_snd_hdr hdr;
-+      /* 0 ... virtio_snd_config::jacks - 1 */
-+      __le32 jack_id;
-+};
-+
-+/* supported jack features */
-+enum {
-+      VIRTIO_SND_JACK_F_REMAP = 0
-+};
-+
-+struct virtio_snd_jack_info {
-+      /* common header */
-+      struct virtio_snd_info hdr;
-+      /* supported feature bit map (1 << VIRTIO_SND_JACK_F_XXX) */
-+      __le32 features;
-+      /* pin configuration (High Definition Audio Specification 7.3.3.31) */
-+      __le32 hda_reg_defconf;
-+      /* pin capabilities (High Definition Audio Specification 7.3.4.9) */
-+      __le32 hda_reg_caps;
-+      /* current jack connection status (0: disconnected, 1: connected) */
-+      __u8 connected;
-+
-+      __u8 padding[7];
-+};
-+
-+/* jack remapping control request */
-+struct virtio_snd_jack_remap {
-+      /* .code = VIRTIO_SND_R_JACK_REMAP */
-+      struct virtio_snd_jack_hdr hdr;
-+      /* selected association number */
-+      __le32 association;
-+      /* selected sequence number */
-+      __le32 sequence;
-+};
-+
-+/*******************************************************************************
-+ * PCM CONTROL MESSAGES
-+ */
-+struct virtio_snd_pcm_hdr {
-+      /* VIRTIO_SND_R_PCM_XXX */
-+      struct virtio_snd_hdr hdr;
-+      /* 0 ... virtio_snd_config::streams - 1 */
-+      __le32 stream_id;
-+};
-+
-+/* supported PCM stream features */
-+enum {
-+      VIRTIO_SND_PCM_F_SHMEM_HOST = 0,
-+      VIRTIO_SND_PCM_F_SHMEM_GUEST,
-+      VIRTIO_SND_PCM_F_MSG_POLLING,
-+      VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS,
-+      VIRTIO_SND_PCM_F_EVT_XRUNS
-+};
-+
-+/* supported PCM sample formats */
-+enum {
-+      /* analog formats (width / physical width) */
-+      VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0,       /*  4 /  4 bits */
-+      VIRTIO_SND_PCM_FMT_MU_LAW,              /*  8 /  8 bits */
-+      VIRTIO_SND_PCM_FMT_A_LAW,               /*  8 /  8 bits */
-+      VIRTIO_SND_PCM_FMT_S8,                  /*  8 /  8 bits */
-+      VIRTIO_SND_PCM_FMT_U8,                  /*  8 /  8 bits */
-+      VIRTIO_SND_PCM_FMT_S16,                 /* 16 / 16 bits */
-+      VIRTIO_SND_PCM_FMT_U16,                 /* 16 / 16 bits */
-+      VIRTIO_SND_PCM_FMT_S18_3,               /* 18 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_U18_3,               /* 18 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_S20_3,               /* 20 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_U20_3,               /* 20 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_S24_3,               /* 24 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_U24_3,               /* 24 / 24 bits */
-+      VIRTIO_SND_PCM_FMT_S20,                 /* 20 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_U20,                 /* 20 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_S24,                 /* 24 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_U24,                 /* 24 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_S32,                 /* 32 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_U32,                 /* 32 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_FLOAT,               /* 32 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_FLOAT64,             /* 64 / 64 bits */
-+      /* digital formats (width / physical width) */
-+      VIRTIO_SND_PCM_FMT_DSD_U8,              /*  8 /  8 bits */
-+      VIRTIO_SND_PCM_FMT_DSD_U16,             /* 16 / 16 bits */
-+      VIRTIO_SND_PCM_FMT_DSD_U32,             /* 32 / 32 bits */
-+      VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME      /* 32 / 32 bits */
-+};
-+
-+/* supported PCM frame rates */
-+enum {
-+      VIRTIO_SND_PCM_RATE_5512 = 0,
-+      VIRTIO_SND_PCM_RATE_8000,
-+      VIRTIO_SND_PCM_RATE_11025,
-+      VIRTIO_SND_PCM_RATE_16000,
-+      VIRTIO_SND_PCM_RATE_22050,
-+      VIRTIO_SND_PCM_RATE_32000,
-+      VIRTIO_SND_PCM_RATE_44100,
-+      VIRTIO_SND_PCM_RATE_48000,
-+      VIRTIO_SND_PCM_RATE_64000,
-+      VIRTIO_SND_PCM_RATE_88200,
-+      VIRTIO_SND_PCM_RATE_96000,
-+      VIRTIO_SND_PCM_RATE_176400,
-+      VIRTIO_SND_PCM_RATE_192000,
-+      VIRTIO_SND_PCM_RATE_384000
-+};
-+
-+struct virtio_snd_pcm_info {
-+      /* common header */
-+      struct virtio_snd_info hdr;
-+      /* supported feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */
-+      __le32 features;
-+      /* supported sample format bit map (1 << VIRTIO_SND_PCM_FMT_XXX) */
-+      __le64 formats;
-+      /* supported frame rate bit map (1 << VIRTIO_SND_PCM_RATE_XXX) */
-+      __le64 rates;
-+      /* dataflow direction (VIRTIO_SND_D_XXX) */
-+      __u8 direction;
-+      /* minimum # of supported channels */
-+      __u8 channels_min;
-+      /* maximum # of supported channels */
-+      __u8 channels_max;
-+
-+      __u8 padding[5];
-+};
-+
-+/* set PCM stream format */
-+struct virtio_snd_pcm_set_params {
-+      /* .code = VIRTIO_SND_R_PCM_SET_PARAMS */
-+      struct virtio_snd_pcm_hdr hdr;
-+      /* size of the hardware buffer */
-+      __le32 buffer_bytes;
-+      /* size of the hardware period */
-+      __le32 period_bytes;
-+      /* selected feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */
-+      __le32 features;
-+      /* selected # of channels */
-+      __u8 channels;
-+      /* selected sample format (VIRTIO_SND_PCM_FMT_XXX) */
-+      __u8 format;
-+      /* selected frame rate (VIRTIO_SND_PCM_RATE_XXX) */
-+      __u8 rate;
-+
-+      __u8 padding;
-+};
-+
-+/*******************************************************************************
-+ * PCM I/O MESSAGES
-+ */
-+
-+/* I/O request header */
-+struct virtio_snd_pcm_xfer {
-+      /* 0 ... virtio_snd_config::streams - 1 */
-+      __le32 stream_id;
-+};
-+
-+/* I/O request status */
-+struct virtio_snd_pcm_status {
-+      /* VIRTIO_SND_S_XXX */
-+      __le32 status;
-+      /* current device latency */
-+      __le32 latency_bytes;
-+};
-+
-+/*******************************************************************************
-+ * CHANNEL MAP CONTROL MESSAGES
-+ */
-+struct virtio_snd_chmap_hdr {
-+      /* VIRTIO_SND_R_CHMAP_XXX */
-+      struct virtio_snd_hdr hdr;
-+      /* 0 ... virtio_snd_config::chmaps - 1 */
-+      __le32 chmap_id;
-+};
-+
-+/* standard channel position definition */
-+enum {
-+      VIRTIO_SND_CHMAP_NONE = 0,      /* undefined */
-+      VIRTIO_SND_CHMAP_NA,            /* silent */
-+      VIRTIO_SND_CHMAP_MONO,          /* mono stream */
-+      VIRTIO_SND_CHMAP_FL,            /* front left */
-+      VIRTIO_SND_CHMAP_FR,            /* front right */
-+      VIRTIO_SND_CHMAP_RL,            /* rear left */
-+      VIRTIO_SND_CHMAP_RR,            /* rear right */
-+      VIRTIO_SND_CHMAP_FC,            /* front center */
-+      VIRTIO_SND_CHMAP_LFE,           /* low frequency (LFE) */
-+      VIRTIO_SND_CHMAP_SL,            /* side left */
-+      VIRTIO_SND_CHMAP_SR,            /* side right */
-+      VIRTIO_SND_CHMAP_RC,            /* rear center */
-+      VIRTIO_SND_CHMAP_FLC,           /* front left center */
-+      VIRTIO_SND_CHMAP_FRC,           /* front right center */
-+      VIRTIO_SND_CHMAP_RLC,           /* rear left center */
-+      VIRTIO_SND_CHMAP_RRC,           /* rear right center */
-+      VIRTIO_SND_CHMAP_FLW,           /* front left wide */
-+      VIRTIO_SND_CHMAP_FRW,           /* front right wide */
-+      VIRTIO_SND_CHMAP_FLH,           /* front left high */
-+      VIRTIO_SND_CHMAP_FCH,           /* front center high */
-+      VIRTIO_SND_CHMAP_FRH,           /* front right high */
-+      VIRTIO_SND_CHMAP_TC,            /* top center */
-+      VIRTIO_SND_CHMAP_TFL,           /* top front left */
-+      VIRTIO_SND_CHMAP_TFR,           /* top front right */
-+      VIRTIO_SND_CHMAP_TFC,           /* top front center */
-+      VIRTIO_SND_CHMAP_TRL,           /* top rear left */
-+      VIRTIO_SND_CHMAP_TRR,           /* top rear right */
-+      VIRTIO_SND_CHMAP_TRC,           /* top rear center */
-+      VIRTIO_SND_CHMAP_TFLC,          /* top front left center */
-+      VIRTIO_SND_CHMAP_TFRC,          /* top front right center */
-+      VIRTIO_SND_CHMAP_TSL,           /* top side left */
-+      VIRTIO_SND_CHMAP_TSR,           /* top side right */
-+      VIRTIO_SND_CHMAP_LLFE,          /* left LFE */
-+      VIRTIO_SND_CHMAP_RLFE,          /* right LFE */
-+      VIRTIO_SND_CHMAP_BC,            /* bottom center */
-+      VIRTIO_SND_CHMAP_BLC,           /* bottom left center */
-+      VIRTIO_SND_CHMAP_BRC            /* bottom right center */
-+};
-+
-+/* maximum possible number of channels */
-+#define VIRTIO_SND_CHMAP_MAX_SIZE     18
-+
-+struct virtio_snd_chmap_info {
-+      /* common header */
-+      struct virtio_snd_info hdr;
-+      /* dataflow direction (VIRTIO_SND_D_XXX) */
-+      __u8 direction;
-+      /* # of valid channel position values */
-+      __u8 channels;
-+      /* channel position values (VIRTIO_SND_CHMAP_XXX) */
-+      __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
-+};
-+
-+#endif /* VIRTIO_SND_IF_H */
-diff --git a/sound/Kconfig b/sound/Kconfig
-index 36785410fbe1..e56d96d2b11c 100644
---- a/sound/Kconfig
-+++ b/sound/Kconfig
-@@ -99,6 +99,8 @@ source "sound/synth/Kconfig"
- source "sound/xen/Kconfig"
-+source "sound/virtio/Kconfig"
-+
- endif # SND
- endif # !UML
-diff --git a/sound/Makefile b/sound/Makefile
-index 797ecdcd35e2..04ef04b1168f 100644
---- a/sound/Makefile
-+++ b/sound/Makefile
-@@ -5,7 +5,8 @@
- obj-$(CONFIG_SOUND) += soundcore.o
- obj-$(CONFIG_DMASOUND) += oss/dmasound/
- obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
--      firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/
-+      firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ \
-+      virtio/
- obj-$(CONFIG_SND_AOA) += aoa/
- # This one must be compilable even if sound is configured out
-diff --git a/sound/virtio/Kconfig b/sound/virtio/Kconfig
-new file mode 100644
-index 000000000000..094cba24ee5b
---- /dev/null
-+++ b/sound/virtio/Kconfig
-@@ -0,0 +1,10 @@
-+# SPDX-License-Identifier: GPL-2.0+
-+# Sound card driver for virtio
-+
-+config SND_VIRTIO
-+      tristate "Virtio sound driver"
-+      depends on VIRTIO
-+      select SND_PCM
-+      select SND_JACK
-+      help
-+          This is the virtual sound driver for virtio. Say Y or M.
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-new file mode 100644
-index 000000000000..8c87ebb9982b
---- /dev/null
-+++ b/sound/virtio/Makefile
-@@ -0,0 +1,7 @@
-+# SPDX-License-Identifier: GPL-2.0+
-+
-+obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
-+
-+virtio_snd-objs := \
-+      virtio_card.o
-+
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-new file mode 100644
-index 000000000000..5a37056858e9
---- /dev/null
-+++ b/sound/virtio/virtio_card.c
-@@ -0,0 +1,324 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/virtio_config.h>
-+#include <sound/initval.h>
-+#include <uapi/linux/virtio_ids.h>
-+
-+#include "virtio_card.h"
-+
-+static void virtsnd_remove(struct virtio_device *vdev);
-+
-+/**
-+ * virtsnd_event_send() - Add an event to the event queue.
-+ * @vqueue: Underlying event virtqueue.
-+ * @event: Event.
-+ * @notify: Indicates whether or not to send a notification to the device.
-+ * @gfp: Kernel flags for memory allocation.
-+ *
-+ * Context: Any context.
-+ */
-+static void virtsnd_event_send(struct virtqueue *vqueue,
-+                             struct virtio_snd_event *event, bool notify,
-+                             gfp_t gfp)
-+{
-+      struct scatterlist sg;
-+      struct scatterlist *psgs[1] = { &sg };
-+
-+      /* reset event content */
-+      memset(event, 0, sizeof(*event));
-+
-+      sg_init_one(&sg, event, sizeof(*event));
-+
-+      if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify)
-+              return;
-+
-+      if (virtqueue_kick_prepare(vqueue))
-+              virtqueue_notify(vqueue);
-+}
-+
-+/**
-+ * virtsnd_event_dispatch() - Dispatch an event from the device side.
-+ * @snd: VirtIO sound device.
-+ * @event: VirtIO sound event.
-+ *
-+ * Context: Any context.
-+ */
-+static void virtsnd_event_dispatch(struct virtio_snd *snd,
-+                                 struct virtio_snd_event *event)
-+{
-+}
-+
-+/**
-+ * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue.
-+ * @vqueue: Underlying event virtqueue.
-+ *
-+ * This callback function is called upon a vring interrupt request from the
-+ * device.
-+ *
-+ * Context: Interrupt context.
-+ */
-+static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
-+{
-+      struct virtio_snd *snd = vqueue->vdev->priv;
-+      struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
-+      struct virtio_snd_event *event;
-+      u32 length;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&queue->lock, flags);
-+      do {
-+              virtqueue_disable_cb(vqueue);
-+              while ((event = virtqueue_get_buf(vqueue, &length))) {
-+                      virtsnd_event_dispatch(snd, event);
-+                      virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
-+              }
-+              if (unlikely(virtqueue_is_broken(vqueue)))
-+                      break;
-+      } while (!virtqueue_enable_cb(vqueue));
-+      spin_unlock_irqrestore(&queue->lock, flags);
-+}
-+
-+/**
-+ * virtsnd_find_vqs() - Enumerate and initialize all virtqueues.
-+ * @snd: VirtIO sound device.
-+ *
-+ * After calling this function, the event queue is disabled.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_find_vqs(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
-+              [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
-+      };
-+      static const char *names[VIRTIO_SND_VQ_MAX] = {
-+              [VIRTIO_SND_VQ_EVENT] = "virtsnd-event"
-+      };
-+      struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
-+      unsigned int i;
-+      unsigned int n;
-+      int rc;
-+
-+      rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
-+                           NULL);
-+      if (rc) {
-+              dev_err(&vdev->dev, "failed to initialize virtqueues\n");
-+              return rc;
-+      }
-+
-+      for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
-+              snd->queues[i].vqueue = vqs[i];
-+
-+      /* Allocate events and populate the event queue */
-+      virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]);
-+
-+      n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]);
-+
-+      snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs),
-+                                      GFP_KERNEL);
-+      if (!snd->event_msgs)
-+              return -ENOMEM;
-+
-+      for (i = 0; i < n; ++i)
-+              virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT],
-+                                 &snd->event_msgs[i], false, GFP_KERNEL);
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_enable_event_vq() - Enable the event virtqueue.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context.
-+ */
-+static void virtsnd_enable_event_vq(struct virtio_snd *snd)
-+{
-+      struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
-+
-+      if (!virtqueue_enable_cb(queue->vqueue))
-+              virtsnd_event_notify_cb(queue->vqueue);
-+}
-+
-+/**
-+ * virtsnd_disable_event_vq() - Disable the event virtqueue.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context.
-+ */
-+static void virtsnd_disable_event_vq(struct virtio_snd *snd)
-+{
-+      struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
-+      struct virtio_snd_event *event;
-+      u32 length;
-+      unsigned long flags;
-+
-+      if (queue->vqueue) {
-+              spin_lock_irqsave(&queue->lock, flags);
-+              virtqueue_disable_cb(queue->vqueue);
-+              while ((event = virtqueue_get_buf(queue->vqueue, &length)))
-+                      virtsnd_event_dispatch(snd, event);
-+              spin_unlock_irqrestore(&queue->lock, flags);
-+      }
-+}
-+
-+/**
-+ * virtsnd_build_devs() - Read configuration and build ALSA devices.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_build_devs(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct device *dev = &vdev->dev;
-+      int rc;
-+
-+      rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-+                        THIS_MODULE, 0, &snd->card);
-+      if (rc < 0)
-+              return rc;
-+
-+      snd->card->private_data = snd;
-+
-+      strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
-+              sizeof(snd->card->driver));
-+      strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
-+              sizeof(snd->card->shortname));
-+      if (dev->parent->bus)
-+              snprintf(snd->card->longname, sizeof(snd->card->longname),
-+                       VIRTIO_SND_CARD_NAME " at %s/%s/%s",
-+                       dev->parent->bus->name, dev_name(dev->parent),
-+                       dev_name(dev));
-+      else
-+              snprintf(snd->card->longname, sizeof(snd->card->longname),
-+                       VIRTIO_SND_CARD_NAME " at %s/%s",
-+                       dev_name(dev->parent), dev_name(dev));
-+
-+      return snd_card_register(snd->card);
-+}
-+
-+/**
-+ * virtsnd_validate() - Validate if the device can be started.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -EINVAL on failure.
-+ */
-+static int virtsnd_validate(struct virtio_device *vdev)
-+{
-+      if (!vdev->config->get) {
-+              dev_err(&vdev->dev, "configuration access disabled\n");
-+              return -EINVAL;
-+      }
-+
-+      if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
-+              dev_err(&vdev->dev,
-+                      "device does not comply with spec version 1.x\n");
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_probe() - Create and initialize the device.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_probe(struct virtio_device *vdev)
-+{
-+      struct virtio_snd *snd;
-+      unsigned int i;
-+      int rc;
-+
-+      snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL);
-+      if (!snd)
-+              return -ENOMEM;
-+
-+      snd->vdev = vdev;
-+
-+      vdev->priv = snd;
-+
-+      for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
-+              spin_lock_init(&snd->queues[i].lock);
-+
-+      rc = virtsnd_find_vqs(snd);
-+      if (rc)
-+              goto on_exit;
-+
-+      virtio_device_ready(vdev);
-+
-+      rc = virtsnd_build_devs(snd);
-+      if (rc)
-+              goto on_exit;
-+
-+      virtsnd_enable_event_vq(snd);
-+
-+on_exit:
-+      if (rc)
-+              virtsnd_remove(vdev);
-+
-+      return rc;
-+}
-+
-+/**
-+ * virtsnd_remove() - Remove VirtIO and ALSA devices.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context that permits to sleep.
-+ */
-+static void virtsnd_remove(struct virtio_device *vdev)
-+{
-+      struct virtio_snd *snd = vdev->priv;
-+
-+      virtsnd_disable_event_vq(snd);
-+
-+      if (snd->card)
-+              snd_card_free(snd->card);
-+
-+      vdev->config->del_vqs(vdev);
-+      vdev->config->reset(vdev);
-+
-+      kfree(snd->event_msgs);
-+}
-+
-+static const struct virtio_device_id id_table[] = {
-+      { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
-+      { 0 },
-+};
-+
-+static struct virtio_driver virtsnd_driver = {
-+      .driver.name = KBUILD_MODNAME,
-+      .driver.owner = THIS_MODULE,
-+      .id_table = id_table,
-+      .validate = virtsnd_validate,
-+      .probe = virtsnd_probe,
-+      .remove = virtsnd_remove,
-+};
-+
-+static int __init init(void)
-+{
-+      return register_virtio_driver(&virtsnd_driver);
-+}
-+module_init(init);
-+
-+static void __exit fini(void)
-+{
-+      unregister_virtio_driver(&virtsnd_driver);
-+}
-+module_exit(fini);
-+
-+MODULE_DEVICE_TABLE(virtio, id_table);
-+MODULE_DESCRIPTION("Virtio sound card driver");
-+MODULE_LICENSE("GPL");
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-new file mode 100644
-index 000000000000..b903b1b12e90
---- /dev/null
-+++ b/sound/virtio/virtio_card.h
-@@ -0,0 +1,65 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#ifndef VIRTIO_SND_CARD_H
-+#define VIRTIO_SND_CARD_H
-+
-+#include <linux/slab.h>
-+#include <linux/virtio.h>
-+#include <sound/core.h>
-+#include <uapi/linux/virtio_snd.h>
-+
-+#define VIRTIO_SND_CARD_DRIVER        "virtio-snd"
-+#define VIRTIO_SND_CARD_NAME  "VirtIO SoundCard"
-+
-+/**
-+ * struct virtio_snd_queue - Virtqueue wrapper structure.
-+ * @lock: Used to synchronize access to a virtqueue.
-+ * @vqueue: Underlying virtqueue.
-+ */
-+struct virtio_snd_queue {
-+      spinlock_t lock;
-+      struct virtqueue *vqueue;
-+};
-+
-+/**
-+ * struct virtio_snd - VirtIO sound card device.
-+ * @vdev: Underlying virtio device.
-+ * @queues: Virtqueue wrappers.
-+ * @card: ALSA sound card.
-+ * @event_msgs: Device events.
-+ */
-+struct virtio_snd {
-+      struct virtio_device *vdev;
-+      struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
-+      struct snd_card *card;
-+      struct virtio_snd_event *event_msgs;
-+};
-+
-+static inline struct virtio_snd_queue *
-+virtsnd_control_queue(struct virtio_snd *snd)
-+{
-+      return &snd->queues[VIRTIO_SND_VQ_CONTROL];
-+}
-+
-+static inline struct virtio_snd_queue *
-+virtsnd_event_queue(struct virtio_snd *snd)
-+{
-+      return &snd->queues[VIRTIO_SND_VQ_EVENT];
-+}
-+
-+static inline struct virtio_snd_queue *
-+virtsnd_tx_queue(struct virtio_snd *snd)
-+{
-+      return &snd->queues[VIRTIO_SND_VQ_TX];
-+}
-+
-+static inline struct virtio_snd_queue *
-+virtsnd_rx_queue(struct virtio_snd *snd)
-+{
-+      return &snd->queues[VIRTIO_SND_VQ_RX];
-+}
-+
-+#endif /* VIRTIO_SND_CARD_H */
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0003-ALSA-virtio-handling-control-messages.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0003-ALSA-virtio-handling-control-messages.patch
deleted file mode 100644 (file)
index 2ee988a..0000000
+++ /dev/null
@@ -1,528 +0,0 @@
-From d4c8a3a4b9de5a25b6963f3ae1b8a5cb32081de5 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:03 +0100
-Subject: [PATCH] ALSA: virtio: handling control messages
-
-The control queue can be used by different parts of the driver to send
-commands to the device. Control messages can be either synchronous or
-asynchronous. The lifetime of a message is controlled by a reference
-count.
-
-Introduce a module parameter to set the message completion timeout:
-  msg_timeout_ms [=1000]
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-4-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile         |   3 +-
- sound/virtio/virtio_card.c    |  13 ++
- sound/virtio/virtio_card.h    |   7 +
- sound/virtio/virtio_ctl_msg.c | 310 ++++++++++++++++++++++++++++++++++
- sound/virtio/virtio_ctl_msg.h |  78 +++++++++
- 5 files changed, 410 insertions(+), 1 deletion(-)
- create mode 100644 sound/virtio/virtio_ctl_msg.c
- create mode 100644 sound/virtio/virtio_ctl_msg.h
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index 8c87ebb9982b..dc551e637441 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -3,5 +3,6 @@
- obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
- virtio_snd-objs := \
--      virtio_card.o
-+      virtio_card.o \
-+      virtio_ctl_msg.o
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index 5a37056858e9..b757b2444078 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -11,6 +11,10 @@
- #include "virtio_card.h"
-+u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC;
-+module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644);
-+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
-+
- static void virtsnd_remove(struct virtio_device *vdev);
- /**
-@@ -96,9 +100,11 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
- {
-       struct virtio_device *vdev = snd->vdev;
-       static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
-+              [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
-               [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
-       };
-       static const char *names[VIRTIO_SND_VQ_MAX] = {
-+              [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
-               [VIRTIO_SND_VQ_EVENT] = "virtsnd-event"
-       };
-       struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
-@@ -226,6 +232,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
-               return -EINVAL;
-       }
-+      if (!virtsnd_msg_timeout_ms) {
-+              dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
-+              return -EINVAL;
-+      }
-+
-       return 0;
- }
-@@ -247,6 +258,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
-               return -ENOMEM;
-       snd->vdev = vdev;
-+      INIT_LIST_HEAD(&snd->ctl_msgs);
-       vdev->priv = snd;
-@@ -283,6 +295,7 @@ static void virtsnd_remove(struct virtio_device *vdev)
-       struct virtio_snd *snd = vdev->priv;
-       virtsnd_disable_event_vq(snd);
-+      virtsnd_ctl_msg_cancel_all(snd);
-       if (snd->card)
-               snd_card_free(snd->card);
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-index b903b1b12e90..1e76eeff160f 100644
---- a/sound/virtio/virtio_card.h
-+++ b/sound/virtio/virtio_card.h
-@@ -11,6 +11,8 @@
- #include <sound/core.h>
- #include <uapi/linux/virtio_snd.h>
-+#include "virtio_ctl_msg.h"
-+
- #define VIRTIO_SND_CARD_DRIVER        "virtio-snd"
- #define VIRTIO_SND_CARD_NAME  "VirtIO SoundCard"
-@@ -29,15 +31,20 @@ struct virtio_snd_queue {
-  * @vdev: Underlying virtio device.
-  * @queues: Virtqueue wrappers.
-  * @card: ALSA sound card.
-+ * @ctl_msgs: Pending control request list.
-  * @event_msgs: Device events.
-  */
- struct virtio_snd {
-       struct virtio_device *vdev;
-       struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
-       struct snd_card *card;
-+      struct list_head ctl_msgs;
-       struct virtio_snd_event *event_msgs;
- };
-+/* Message completion timeout in milliseconds (module parameter). */
-+extern u32 virtsnd_msg_timeout_ms;
-+
- static inline struct virtio_snd_queue *
- virtsnd_control_queue(struct virtio_snd *snd)
- {
-diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c
-new file mode 100644
-index 000000000000..26ff7e7cc041
---- /dev/null
-+++ b/sound/virtio/virtio_ctl_msg.c
-@@ -0,0 +1,310 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <linux/moduleparam.h>
-+#include <linux/virtio_config.h>
-+
-+#include "virtio_card.h"
-+
-+/**
-+ * struct virtio_snd_msg - Control message.
-+ * @sg_request: Scattergather list containing a device request (header).
-+ * @sg_response: Scattergather list containing a device response (status).
-+ * @list: Pending message list entry.
-+ * @notify: Request completed notification.
-+ * @ref_count: Reference count used to manage a message lifetime.
-+ */
-+struct virtio_snd_msg {
-+      struct scatterlist sg_request;
-+      struct scatterlist sg_response;
-+      struct list_head list;
-+      struct completion notify;
-+      refcount_t ref_count;
-+};
-+
-+/**
-+ * virtsnd_ctl_msg_ref() - Increment reference counter for the message.
-+ * @msg: Control message.
-+ *
-+ * Context: Any context.
-+ */
-+void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg)
-+{
-+      refcount_inc(&msg->ref_count);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_unref() - Decrement reference counter for the message.
-+ * @msg: Control message.
-+ *
-+ * The message will be freed when the ref_count value is 0.
-+ *
-+ * Context: Any context.
-+ */
-+void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg)
-+{
-+      if (refcount_dec_and_test(&msg->ref_count))
-+              kfree(msg);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_request() - Get a pointer to the request header.
-+ * @msg: Control message.
-+ *
-+ * Context: Any context.
-+ */
-+void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg)
-+{
-+      return sg_virt(&msg->sg_request);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_request() - Get a pointer to the response header.
-+ * @msg: Control message.
-+ *
-+ * Context: Any context.
-+ */
-+void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg)
-+{
-+      return sg_virt(&msg->sg_response);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_alloc() - Allocate and initialize a control message.
-+ * @request_size: Size of request header.
-+ * @response_size: Size of response header.
-+ * @gfp: Kernel flags for memory allocation.
-+ *
-+ * The message will be automatically freed when the ref_count value is 0.
-+ *
-+ * Context: Any context. May sleep if @gfp flags permit.
-+ * Return: Allocated message on success, NULL on failure.
-+ */
-+struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size,
-+                                           size_t response_size, gfp_t gfp)
-+{
-+      struct virtio_snd_msg *msg;
-+
-+      if (!request_size || !response_size)
-+              return NULL;
-+
-+      msg = kzalloc(sizeof(*msg) + request_size + response_size, gfp);
-+      if (!msg)
-+              return NULL;
-+
-+      sg_init_one(&msg->sg_request, (u8 *)msg + sizeof(*msg), request_size);
-+      sg_init_one(&msg->sg_response, (u8 *)msg + sizeof(*msg) + request_size,
-+                  response_size);
-+
-+      INIT_LIST_HEAD(&msg->list);
-+      init_completion(&msg->notify);
-+      /* This reference is dropped in virtsnd_ctl_msg_complete(). */
-+      refcount_set(&msg->ref_count, 1);
-+
-+      return msg;
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_send() - Send a control message.
-+ * @snd: VirtIO sound device.
-+ * @msg: Control message.
-+ * @out_sgs: Additional sg-list to attach to the request header (may be NULL).
-+ * @in_sgs: Additional sg-list to attach to the response header (may be NULL).
-+ * @nowait: Flag indicating whether to wait for completion.
-+ *
-+ * Context: Any context. Takes and releases the control queue spinlock.
-+ *          May sleep if @nowait is false.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg,
-+                       struct scatterlist *out_sgs,
-+                       struct scatterlist *in_sgs, bool nowait)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_snd_queue *queue = virtsnd_control_queue(snd);
-+      unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
-+      struct virtio_snd_hdr *request = virtsnd_ctl_msg_request(msg);
-+      struct virtio_snd_hdr *response = virtsnd_ctl_msg_response(msg);
-+      unsigned int nouts = 0;
-+      unsigned int nins = 0;
-+      struct scatterlist *psgs[4];
-+      bool notify = false;
-+      unsigned long flags;
-+      int rc;
-+
-+      virtsnd_ctl_msg_ref(msg);
-+
-+      /* Set the default status in case the message was canceled. */
-+      response->code = cpu_to_le32(VIRTIO_SND_S_IO_ERR);
-+
-+      psgs[nouts++] = &msg->sg_request;
-+      if (out_sgs)
-+              psgs[nouts++] = out_sgs;
-+
-+      psgs[nouts + nins++] = &msg->sg_response;
-+      if (in_sgs)
-+              psgs[nouts + nins++] = in_sgs;
-+
-+      spin_lock_irqsave(&queue->lock, flags);
-+      rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg,
-+                             GFP_ATOMIC);
-+      if (!rc) {
-+              notify = virtqueue_kick_prepare(queue->vqueue);
-+
-+              list_add_tail(&msg->list, &snd->ctl_msgs);
-+      }
-+      spin_unlock_irqrestore(&queue->lock, flags);
-+
-+      if (rc) {
-+              dev_err(&vdev->dev, "failed to send control message (0x%08x)\n",
-+                      le32_to_cpu(request->code));
-+
-+              /*
-+               * Since in this case virtsnd_ctl_msg_complete() will not be
-+               * called, it is necessary to decrement the reference count.
-+               */
-+              virtsnd_ctl_msg_unref(msg);
-+
-+              goto on_exit;
-+      }
-+
-+      if (notify)
-+              virtqueue_notify(queue->vqueue);
-+
-+      if (nowait)
-+              goto on_exit;
-+
-+      rc = wait_for_completion_interruptible_timeout(&msg->notify, js);
-+      if (rc <= 0) {
-+              if (!rc) {
-+                      dev_err(&vdev->dev,
-+                              "control message (0x%08x) timeout\n",
-+                              le32_to_cpu(request->code));
-+                      rc = -ETIMEDOUT;
-+              }
-+
-+              goto on_exit;
-+      }
-+
-+      switch (le32_to_cpu(response->code)) {
-+      case VIRTIO_SND_S_OK:
-+              rc = 0;
-+              break;
-+      case VIRTIO_SND_S_NOT_SUPP:
-+              rc = -EOPNOTSUPP;
-+              break;
-+      case VIRTIO_SND_S_IO_ERR:
-+              rc = -EIO;
-+              break;
-+      default:
-+              rc = -EINVAL;
-+              break;
-+      }
-+
-+on_exit:
-+      virtsnd_ctl_msg_unref(msg);
-+
-+      return rc;
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_complete() - Complete a control message.
-+ * @msg: Control message.
-+ *
-+ * Context: Any context. Expects the control queue spinlock to be held by
-+ *          caller.
-+ */
-+void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg)
-+{
-+      list_del(&msg->list);
-+      complete(&msg->notify);
-+
-+      virtsnd_ctl_msg_unref(msg);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_cancel_all() - Cancel all pending control messages.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context.
-+ */
-+void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd)
-+{
-+      struct virtio_snd_queue *queue = virtsnd_control_queue(snd);
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&queue->lock, flags);
-+      while (!list_empty(&snd->ctl_msgs)) {
-+              struct virtio_snd_msg *msg =
-+                      list_first_entry(&snd->ctl_msgs, struct virtio_snd_msg,
-+                                       list);
-+
-+              virtsnd_ctl_msg_complete(msg);
-+      }
-+      spin_unlock_irqrestore(&queue->lock, flags);
-+}
-+
-+/**
-+ * virtsnd_ctl_query_info() - Query the item configuration from the device.
-+ * @snd: VirtIO sound device.
-+ * @command: Control request code (VIRTIO_SND_R_XXX_INFO).
-+ * @start_id: Item start identifier.
-+ * @count: Item count to query.
-+ * @size: Item information size in bytes.
-+ * @info: Buffer for storing item information.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id,
-+                         int count, size_t size, void *info)
-+{
-+      struct virtio_snd_msg *msg;
-+      struct virtio_snd_query_info *query;
-+      struct scatterlist sg;
-+
-+      msg = virtsnd_ctl_msg_alloc(sizeof(*query),
-+                                  sizeof(struct virtio_snd_hdr), GFP_KERNEL);
-+      if (!msg)
-+              return -ENOMEM;
-+
-+      query = virtsnd_ctl_msg_request(msg);
-+      query->hdr.code = cpu_to_le32(command);
-+      query->start_id = cpu_to_le32(start_id);
-+      query->count = cpu_to_le32(count);
-+      query->size = cpu_to_le32(size);
-+
-+      sg_init_one(&sg, info, count * size);
-+
-+      return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false);
-+}
-+
-+/**
-+ * virtsnd_ctl_notify_cb() - Process all completed control messages.
-+ * @vqueue: Underlying control virtqueue.
-+ *
-+ * This callback function is called upon a vring interrupt request from the
-+ * device.
-+ *
-+ * Context: Interrupt context. Takes and releases the control queue spinlock.
-+ */
-+void virtsnd_ctl_notify_cb(struct virtqueue *vqueue)
-+{
-+      struct virtio_snd *snd = vqueue->vdev->priv;
-+      struct virtio_snd_queue *queue = virtsnd_control_queue(snd);
-+      struct virtio_snd_msg *msg;
-+      u32 length;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&queue->lock, flags);
-+      do {
-+              virtqueue_disable_cb(vqueue);
-+              while ((msg = virtqueue_get_buf(vqueue, &length)))
-+                      virtsnd_ctl_msg_complete(msg);
-+              if (unlikely(virtqueue_is_broken(vqueue)))
-+                      break;
-+      } while (!virtqueue_enable_cb(vqueue));
-+      spin_unlock_irqrestore(&queue->lock, flags);
-+}
-diff --git a/sound/virtio/virtio_ctl_msg.h b/sound/virtio/virtio_ctl_msg.h
-new file mode 100644
-index 000000000000..7f4db044f28e
---- /dev/null
-+++ b/sound/virtio/virtio_ctl_msg.h
-@@ -0,0 +1,78 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#ifndef VIRTIO_SND_MSG_H
-+#define VIRTIO_SND_MSG_H
-+
-+#include <linux/atomic.h>
-+#include <linux/virtio.h>
-+
-+struct virtio_snd;
-+struct virtio_snd_msg;
-+
-+void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg);
-+
-+void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg);
-+
-+void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg);
-+
-+void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg);
-+
-+struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size,
-+                                           size_t response_size, gfp_t gfp);
-+
-+int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg,
-+                       struct scatterlist *out_sgs,
-+                       struct scatterlist *in_sgs, bool nowait);
-+
-+/**
-+ * virtsnd_ctl_msg_send_sync() - Simplified sending of synchronous message.
-+ * @snd: VirtIO sound device.
-+ * @msg: Control message.
-+ *
-+ * After returning from this function, the message will be deleted. If message
-+ * content is still needed, the caller must additionally to
-+ * virtsnd_ctl_msg_ref/unref() it.
-+ *
-+ * The msg_timeout_ms module parameter defines the message completion timeout.
-+ * If the message is not completed within this time, the function will return an
-+ * error.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ *
-+ * The return value is a message status code (VIRTIO_SND_S_XXX) converted to an
-+ * appropriate -errno value.
-+ */
-+static inline int virtsnd_ctl_msg_send_sync(struct virtio_snd *snd,
-+                                          struct virtio_snd_msg *msg)
-+{
-+      return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, false);
-+}
-+
-+/**
-+ * virtsnd_ctl_msg_send_async() - Simplified sending of asynchronous message.
-+ * @snd: VirtIO sound device.
-+ * @msg: Control message.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static inline int virtsnd_ctl_msg_send_async(struct virtio_snd *snd,
-+                                           struct virtio_snd_msg *msg)
-+{
-+      return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, true);
-+}
-+
-+void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd);
-+
-+void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg);
-+
-+int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id,
-+                         int count, size_t size, void *info);
-+
-+void virtsnd_ctl_notify_cb(struct virtqueue *vqueue);
-+
-+#endif /* VIRTIO_SND_MSG_H */
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0004-ALSA-virtio-build-PCM-devices-and-substream-hardware.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0004-ALSA-virtio-build-PCM-devices-and-substream-hardware.patch
deleted file mode 100644 (file)
index 27ae9a8..0000000
+++ /dev/null
@@ -1,703 +0,0 @@
-From 12e4e501f9662a02e61acb5966fdceeffb0ff16d Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:04 +0100
-Subject: [PATCH] ALSA: virtio: build PCM devices and substream hardware
- descriptors
-
-Like the HDA specification, the virtio sound device specification links
-PCM substreams, jacks and PCM channel maps into functional groups. For
-each discovered group, a PCM device is created, the number of which
-coincides with the group number.
-
-Introduce the module parameters for setting the hardware buffer
-parameters:
-  pcm_buffer_ms [=160]
-  pcm_periods_min [=2]
-  pcm_periods_max [=16]
-  pcm_period_ms_min [=10]
-  pcm_period_ms_max [=80]
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-5-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile      |   3 +-
- sound/virtio/virtio_card.c |  18 ++
- sound/virtio/virtio_card.h |  10 +
- sound/virtio/virtio_pcm.c  | 479 +++++++++++++++++++++++++++++++++++++
- sound/virtio/virtio_pcm.h  |  72 ++++++
- 5 files changed, 581 insertions(+), 1 deletion(-)
- create mode 100644 sound/virtio/virtio_pcm.c
- create mode 100644 sound/virtio/virtio_pcm.h
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index dc551e637441..69162a545a41 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -4,5 +4,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
- virtio_snd-objs := \
-       virtio_card.o \
--      virtio_ctl_msg.o
-+      virtio_ctl_msg.o \
-+      virtio_pcm.o
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index b757b2444078..11c76ee311b7 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -209,6 +209,16 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
-                        VIRTIO_SND_CARD_NAME " at %s/%s",
-                        dev_name(dev->parent), dev_name(dev));
-+      rc = virtsnd_pcm_parse_cfg(snd);
-+      if (rc)
-+              return rc;
-+
-+      if (snd->nsubstreams) {
-+              rc = virtsnd_pcm_build_devs(snd);
-+              if (rc)
-+                      return rc;
-+      }
-+
-       return snd_card_register(snd->card);
- }
-@@ -237,6 +247,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
-               return -EINVAL;
-       }
-+      if (virtsnd_pcm_validate(vdev))
-+              return -EINVAL;
-+
-       return 0;
- }
-@@ -259,6 +272,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
-       snd->vdev = vdev;
-       INIT_LIST_HEAD(&snd->ctl_msgs);
-+      INIT_LIST_HEAD(&snd->pcm_list);
-       vdev->priv = snd;
-@@ -293,6 +307,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
- static void virtsnd_remove(struct virtio_device *vdev)
- {
-       struct virtio_snd *snd = vdev->priv;
-+      unsigned int i;
-       virtsnd_disable_event_vq(snd);
-       virtsnd_ctl_msg_cancel_all(snd);
-@@ -303,6 +318,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
-       vdev->config->del_vqs(vdev);
-       vdev->config->reset(vdev);
-+      for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
-+              cancel_work_sync(&snd->substreams[i].elapsed_period);
-+
-       kfree(snd->event_msgs);
- }
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-index 1e76eeff160f..77a1b7255370 100644
---- a/sound/virtio/virtio_card.h
-+++ b/sound/virtio/virtio_card.h
-@@ -12,9 +12,13 @@
- #include <uapi/linux/virtio_snd.h>
- #include "virtio_ctl_msg.h"
-+#include "virtio_pcm.h"
- #define VIRTIO_SND_CARD_DRIVER        "virtio-snd"
- #define VIRTIO_SND_CARD_NAME  "VirtIO SoundCard"
-+#define VIRTIO_SND_PCM_NAME   "VirtIO PCM"
-+
-+struct virtio_pcm_substream;
- /**
-  * struct virtio_snd_queue - Virtqueue wrapper structure.
-@@ -33,6 +37,9 @@ struct virtio_snd_queue {
-  * @card: ALSA sound card.
-  * @ctl_msgs: Pending control request list.
-  * @event_msgs: Device events.
-+ * @pcm_list: VirtIO PCM device list.
-+ * @substreams: VirtIO PCM substreams.
-+ * @nsubstreams: Number of PCM substreams.
-  */
- struct virtio_snd {
-       struct virtio_device *vdev;
-@@ -40,6 +47,9 @@ struct virtio_snd {
-       struct snd_card *card;
-       struct list_head ctl_msgs;
-       struct virtio_snd_event *event_msgs;
-+      struct list_head pcm_list;
-+      struct virtio_pcm_substream *substreams;
-+      u32 nsubstreams;
- };
- /* Message completion timeout in milliseconds (module parameter). */
-diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
-new file mode 100644
-index 000000000000..e16567e2e214
---- /dev/null
-+++ b/sound/virtio/virtio_pcm.c
-@@ -0,0 +1,479 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <linux/moduleparam.h>
-+#include <linux/virtio_config.h>
-+
-+#include "virtio_card.h"
-+
-+static u32 pcm_buffer_ms = 160;
-+module_param(pcm_buffer_ms, uint, 0644);
-+MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds");
-+
-+static u32 pcm_periods_min = 2;
-+module_param(pcm_periods_min, uint, 0644);
-+MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods");
-+
-+static u32 pcm_periods_max = 16;
-+module_param(pcm_periods_max, uint, 0644);
-+MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods");
-+
-+static u32 pcm_period_ms_min = 10;
-+module_param(pcm_period_ms_min, uint, 0644);
-+MODULE_PARM_DESC(pcm_period_ms_min, "Minimum PCM period time in milliseconds");
-+
-+static u32 pcm_period_ms_max = 80;
-+module_param(pcm_period_ms_max, uint, 0644);
-+MODULE_PARM_DESC(pcm_period_ms_max, "Maximum PCM period time in milliseconds");
-+
-+/* Map for converting VirtIO format to ALSA format. */
-+static const snd_pcm_format_t g_v2a_format_map[] = {
-+      [VIRTIO_SND_PCM_FMT_IMA_ADPCM] = SNDRV_PCM_FORMAT_IMA_ADPCM,
-+      [VIRTIO_SND_PCM_FMT_MU_LAW] = SNDRV_PCM_FORMAT_MU_LAW,
-+      [VIRTIO_SND_PCM_FMT_A_LAW] = SNDRV_PCM_FORMAT_A_LAW,
-+      [VIRTIO_SND_PCM_FMT_S8] = SNDRV_PCM_FORMAT_S8,
-+      [VIRTIO_SND_PCM_FMT_U8] = SNDRV_PCM_FORMAT_U8,
-+      [VIRTIO_SND_PCM_FMT_S16] = SNDRV_PCM_FORMAT_S16_LE,
-+      [VIRTIO_SND_PCM_FMT_U16] = SNDRV_PCM_FORMAT_U16_LE,
-+      [VIRTIO_SND_PCM_FMT_S18_3] = SNDRV_PCM_FORMAT_S18_3LE,
-+      [VIRTIO_SND_PCM_FMT_U18_3] = SNDRV_PCM_FORMAT_U18_3LE,
-+      [VIRTIO_SND_PCM_FMT_S20_3] = SNDRV_PCM_FORMAT_S20_3LE,
-+      [VIRTIO_SND_PCM_FMT_U20_3] = SNDRV_PCM_FORMAT_U20_3LE,
-+      [VIRTIO_SND_PCM_FMT_S24_3] = SNDRV_PCM_FORMAT_S24_3LE,
-+      [VIRTIO_SND_PCM_FMT_U24_3] = SNDRV_PCM_FORMAT_U24_3LE,
-+      [VIRTIO_SND_PCM_FMT_S20] = SNDRV_PCM_FORMAT_S20_LE,
-+      [VIRTIO_SND_PCM_FMT_U20] = SNDRV_PCM_FORMAT_U20_LE,
-+      [VIRTIO_SND_PCM_FMT_S24] = SNDRV_PCM_FORMAT_S24_LE,
-+      [VIRTIO_SND_PCM_FMT_U24] = SNDRV_PCM_FORMAT_U24_LE,
-+      [VIRTIO_SND_PCM_FMT_S32] = SNDRV_PCM_FORMAT_S32_LE,
-+      [VIRTIO_SND_PCM_FMT_U32] = SNDRV_PCM_FORMAT_U32_LE,
-+      [VIRTIO_SND_PCM_FMT_FLOAT] = SNDRV_PCM_FORMAT_FLOAT_LE,
-+      [VIRTIO_SND_PCM_FMT_FLOAT64] = SNDRV_PCM_FORMAT_FLOAT64_LE,
-+      [VIRTIO_SND_PCM_FMT_DSD_U8] = SNDRV_PCM_FORMAT_DSD_U8,
-+      [VIRTIO_SND_PCM_FMT_DSD_U16] = SNDRV_PCM_FORMAT_DSD_U16_LE,
-+      [VIRTIO_SND_PCM_FMT_DSD_U32] = SNDRV_PCM_FORMAT_DSD_U32_LE,
-+      [VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME] =
-+              SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
-+};
-+
-+/* Map for converting VirtIO frame rate to ALSA frame rate. */
-+struct virtsnd_v2a_rate {
-+      unsigned int alsa_bit;
-+      unsigned int rate;
-+};
-+
-+static const struct virtsnd_v2a_rate g_v2a_rate_map[] = {
-+      [VIRTIO_SND_PCM_RATE_5512] = { SNDRV_PCM_RATE_5512, 5512 },
-+      [VIRTIO_SND_PCM_RATE_8000] = { SNDRV_PCM_RATE_8000, 8000 },
-+      [VIRTIO_SND_PCM_RATE_11025] = { SNDRV_PCM_RATE_11025, 11025 },
-+      [VIRTIO_SND_PCM_RATE_16000] = { SNDRV_PCM_RATE_16000, 16000 },
-+      [VIRTIO_SND_PCM_RATE_22050] = { SNDRV_PCM_RATE_22050, 22050 },
-+      [VIRTIO_SND_PCM_RATE_32000] = { SNDRV_PCM_RATE_32000, 32000 },
-+      [VIRTIO_SND_PCM_RATE_44100] = { SNDRV_PCM_RATE_44100, 44100 },
-+      [VIRTIO_SND_PCM_RATE_48000] = { SNDRV_PCM_RATE_48000, 48000 },
-+      [VIRTIO_SND_PCM_RATE_64000] = { SNDRV_PCM_RATE_64000, 64000 },
-+      [VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 },
-+      [VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 },
-+      [VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 },
-+      [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 }
-+};
-+
-+/**
-+ * virtsnd_pcm_build_hw() - Parse substream config and build HW descriptor.
-+ * @vss: VirtIO substream.
-+ * @info: VirtIO substream information entry.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -EINVAL if configuration is invalid.
-+ */
-+static int virtsnd_pcm_build_hw(struct virtio_pcm_substream *vss,
-+                              struct virtio_snd_pcm_info *info)
-+{
-+      struct virtio_device *vdev = vss->snd->vdev;
-+      unsigned int i;
-+      u64 values;
-+      size_t sample_max = 0;
-+      size_t sample_min = 0;
-+
-+      vss->features = le32_to_cpu(info->features);
-+
-+      /*
-+       * TODO: set SNDRV_PCM_INFO_{BATCH,BLOCK_TRANSFER} if device supports
-+       * only message-based transport.
-+       */
-+      vss->hw.info =
-+              SNDRV_PCM_INFO_MMAP |
-+              SNDRV_PCM_INFO_MMAP_VALID |
-+              SNDRV_PCM_INFO_BATCH |
-+              SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+              SNDRV_PCM_INFO_INTERLEAVED |
-+              SNDRV_PCM_INFO_PAUSE;
-+
-+      if (!info->channels_min || info->channels_min > info->channels_max) {
-+              dev_err(&vdev->dev,
-+                      "SID %u: invalid channel range [%u %u]\n",
-+                      vss->sid, info->channels_min, info->channels_max);
-+              return -EINVAL;
-+      }
-+
-+      vss->hw.channels_min = info->channels_min;
-+      vss->hw.channels_max = info->channels_max;
-+
-+      values = le64_to_cpu(info->formats);
-+
-+      vss->hw.formats = 0;
-+
-+      for (i = 0; i < ARRAY_SIZE(g_v2a_format_map); ++i)
-+              if (values & (1ULL << i)) {
-+                      snd_pcm_format_t alsa_fmt = g_v2a_format_map[i];
-+                      int bytes = snd_pcm_format_physical_width(alsa_fmt) / 8;
-+
-+                      if (!sample_min || sample_min > bytes)
-+                              sample_min = bytes;
-+
-+                      if (sample_max < bytes)
-+                              sample_max = bytes;
-+
-+                      vss->hw.formats |= pcm_format_to_bits(alsa_fmt);
-+              }
-+
-+      if (!vss->hw.formats) {
-+              dev_err(&vdev->dev,
-+                      "SID %u: no supported PCM sample formats found\n",
-+                      vss->sid);
-+              return -EINVAL;
-+      }
-+
-+      values = le64_to_cpu(info->rates);
-+
-+      vss->hw.rates = 0;
-+
-+      for (i = 0; i < ARRAY_SIZE(g_v2a_rate_map); ++i)
-+              if (values & (1ULL << i)) {
-+                      if (!vss->hw.rate_min ||
-+                          vss->hw.rate_min > g_v2a_rate_map[i].rate)
-+                              vss->hw.rate_min = g_v2a_rate_map[i].rate;
-+
-+                      if (vss->hw.rate_max < g_v2a_rate_map[i].rate)
-+                              vss->hw.rate_max = g_v2a_rate_map[i].rate;
-+
-+                      vss->hw.rates |= g_v2a_rate_map[i].alsa_bit;
-+              }
-+
-+      if (!vss->hw.rates) {
-+              dev_err(&vdev->dev,
-+                      "SID %u: no supported PCM frame rates found\n",
-+                      vss->sid);
-+              return -EINVAL;
-+      }
-+
-+      vss->hw.periods_min = pcm_periods_min;
-+      vss->hw.periods_max = pcm_periods_max;
-+
-+      /*
-+       * We must ensure that there is enough space in the buffer to store
-+       * pcm_buffer_ms ms for the combination (Cmax, Smax, Rmax), where:
-+       *   Cmax = maximum supported number of channels,
-+       *   Smax = maximum supported sample size in bytes,
-+       *   Rmax = maximum supported frame rate.
-+       */
-+      vss->hw.buffer_bytes_max =
-+              PAGE_ALIGN(sample_max * vss->hw.channels_max * pcm_buffer_ms *
-+                         (vss->hw.rate_max / MSEC_PER_SEC));
-+
-+      /*
-+       * We must ensure that the minimum period size is enough to store
-+       * pcm_period_ms_min ms for the combination (Cmin, Smin, Rmin), where:
-+       *   Cmin = minimum supported number of channels,
-+       *   Smin = minimum supported sample size in bytes,
-+       *   Rmin = minimum supported frame rate.
-+       */
-+      vss->hw.period_bytes_min =
-+              sample_min * vss->hw.channels_min * pcm_period_ms_min *
-+              (vss->hw.rate_min / MSEC_PER_SEC);
-+
-+      /*
-+       * We must ensure that the maximum period size is enough to store
-+       * pcm_period_ms_max ms for the combination (Cmax, Smax, Rmax).
-+       */
-+      vss->hw.period_bytes_max =
-+              sample_max * vss->hw.channels_max * pcm_period_ms_max *
-+              (vss->hw.rate_max / MSEC_PER_SEC);
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_find() - Find the PCM device for the specified node ID.
-+ * @snd: VirtIO sound device.
-+ * @nid: Function node ID.
-+ *
-+ * Context: Any context.
-+ * Return: a pointer to the PCM device or ERR_PTR(-ENOENT).
-+ */
-+struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid)
-+{
-+      struct virtio_pcm *vpcm;
-+
-+      list_for_each_entry(vpcm, &snd->pcm_list, list)
-+              if (vpcm->nid == nid)
-+                      return vpcm;
-+
-+      return ERR_PTR(-ENOENT);
-+}
-+
-+/**
-+ * virtsnd_pcm_find_or_create() - Find or create the PCM device for the
-+ *                                specified node ID.
-+ * @snd: VirtIO sound device.
-+ * @nid: Function node ID.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: a pointer to the PCM device or ERR_PTR(-errno).
-+ */
-+struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_pcm *vpcm;
-+
-+      vpcm = virtsnd_pcm_find(snd, nid);
-+      if (!IS_ERR(vpcm))
-+              return vpcm;
-+
-+      vpcm = devm_kzalloc(&vdev->dev, sizeof(*vpcm), GFP_KERNEL);
-+      if (!vpcm)
-+              return ERR_PTR(-ENOMEM);
-+
-+      vpcm->nid = nid;
-+      list_add_tail(&vpcm->list, &snd->pcm_list);
-+
-+      return vpcm;
-+}
-+
-+/**
-+ * virtsnd_pcm_validate() - Validate if the device can be started.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -EINVAL on failure.
-+ */
-+int virtsnd_pcm_validate(struct virtio_device *vdev)
-+{
-+      if (pcm_periods_min < 2 || pcm_periods_min > pcm_periods_max) {
-+              dev_err(&vdev->dev,
-+                      "invalid range [%u %u] of the number of PCM periods\n",
-+                      pcm_periods_min, pcm_periods_max);
-+              return -EINVAL;
-+      }
-+
-+      if (!pcm_period_ms_min || pcm_period_ms_min > pcm_period_ms_max) {
-+              dev_err(&vdev->dev,
-+                      "invalid range [%u %u] of the size of the PCM period\n",
-+                      pcm_period_ms_min, pcm_period_ms_max);
-+              return -EINVAL;
-+      }
-+
-+      if (pcm_buffer_ms < pcm_periods_min * pcm_period_ms_min) {
-+              dev_err(&vdev->dev,
-+                      "pcm_buffer_ms(=%u) value cannot be < %u ms\n",
-+                      pcm_buffer_ms, pcm_periods_min * pcm_period_ms_min);
-+              return -EINVAL;
-+      }
-+
-+      if (pcm_period_ms_max > pcm_buffer_ms / 2) {
-+              dev_err(&vdev->dev,
-+                      "pcm_period_ms_max(=%u) value cannot be > %u ms\n",
-+                      pcm_period_ms_max, pcm_buffer_ms / 2);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_period_elapsed() - Kernel work function to handle the elapsed
-+ *                                period state.
-+ * @work: Elapsed period work.
-+ *
-+ * The main purpose of this function is to call snd_pcm_period_elapsed() in
-+ * a process context, not in an interrupt context. This is necessary because PCM
-+ * devices operate in non-atomic mode.
-+ *
-+ * Context: Process context.
-+ */
-+static void virtsnd_pcm_period_elapsed(struct work_struct *work)
-+{
-+      struct virtio_pcm_substream *vss =
-+              container_of(work, struct virtio_pcm_substream, elapsed_period);
-+
-+      snd_pcm_period_elapsed(vss->substream);
-+}
-+
-+/**
-+ * virtsnd_pcm_parse_cfg() - Parse the stream configuration.
-+ * @snd: VirtIO sound device.
-+ *
-+ * This function is called during initial device initialization.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_snd_pcm_info *info;
-+      u32 i;
-+      int rc;
-+
-+      virtio_cread_le(vdev, struct virtio_snd_config, streams,
-+                      &snd->nsubstreams);
-+      if (!snd->nsubstreams)
-+              return 0;
-+
-+      snd->substreams = devm_kcalloc(&vdev->dev, snd->nsubstreams,
-+                                     sizeof(*snd->substreams), GFP_KERNEL);
-+      if (!snd->substreams)
-+              return -ENOMEM;
-+
-+      info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return -ENOMEM;
-+
-+      rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_PCM_INFO, 0,
-+                                  snd->nsubstreams, sizeof(*info), info);
-+      if (rc)
-+              goto on_exit;
-+
-+      for (i = 0; i < snd->nsubstreams; ++i) {
-+              struct virtio_pcm_substream *vss = &snd->substreams[i];
-+              struct virtio_pcm *vpcm;
-+
-+              vss->snd = snd;
-+              vss->sid = i;
-+              INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed);
-+
-+              rc = virtsnd_pcm_build_hw(vss, &info[i]);
-+              if (rc)
-+                      goto on_exit;
-+
-+              vss->nid = le32_to_cpu(info[i].hdr.hda_fn_nid);
-+
-+              vpcm = virtsnd_pcm_find_or_create(snd, vss->nid);
-+              if (IS_ERR(vpcm)) {
-+                      rc = PTR_ERR(vpcm);
-+                      goto on_exit;
-+              }
-+
-+              switch (info[i].direction) {
-+              case VIRTIO_SND_D_OUTPUT:
-+                      vss->direction = SNDRV_PCM_STREAM_PLAYBACK;
-+                      break;
-+              case VIRTIO_SND_D_INPUT:
-+                      vss->direction = SNDRV_PCM_STREAM_CAPTURE;
-+                      break;
-+              default:
-+                      dev_err(&vdev->dev, "SID %u: unknown direction (%u)\n",
-+                              vss->sid, info[i].direction);
-+                      rc = -EINVAL;
-+                      goto on_exit;
-+              }
-+
-+              vpcm->streams[vss->direction].nsubstreams++;
-+      }
-+
-+on_exit:
-+      kfree(info);
-+
-+      return rc;
-+}
-+
-+/**
-+ * virtsnd_pcm_build_devs() - Build ALSA PCM devices.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_pcm_build_devs(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_pcm *vpcm;
-+      u32 i;
-+      int rc;
-+
-+      list_for_each_entry(vpcm, &snd->pcm_list, list) {
-+              unsigned int npbs =
-+                      vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK].nsubstreams;
-+              unsigned int ncps =
-+                      vpcm->streams[SNDRV_PCM_STREAM_CAPTURE].nsubstreams;
-+
-+              if (!npbs && !ncps)
-+                      continue;
-+
-+              rc = snd_pcm_new(snd->card, VIRTIO_SND_CARD_DRIVER, vpcm->nid,
-+                               npbs, ncps, &vpcm->pcm);
-+              if (rc) {
-+                      dev_err(&vdev->dev, "snd_pcm_new[%u] failed: %d\n",
-+                              vpcm->nid, rc);
-+                      return rc;
-+              }
-+
-+              vpcm->pcm->info_flags = 0;
-+              vpcm->pcm->dev_class = SNDRV_PCM_CLASS_GENERIC;
-+              vpcm->pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-+              snprintf(vpcm->pcm->name, sizeof(vpcm->pcm->name),
-+                       VIRTIO_SND_PCM_NAME " %u", vpcm->pcm->device);
-+              vpcm->pcm->private_data = vpcm;
-+              vpcm->pcm->nonatomic = true;
-+
-+              for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) {
-+                      struct virtio_pcm_stream *stream = &vpcm->streams[i];
-+
-+                      if (!stream->nsubstreams)
-+                              continue;
-+
-+                      stream->substreams =
-+                              devm_kcalloc(&vdev->dev, stream->nsubstreams,
-+                                           sizeof(*stream->substreams),
-+                                           GFP_KERNEL);
-+                      if (!stream->substreams)
-+                              return -ENOMEM;
-+
-+                      stream->nsubstreams = 0;
-+              }
-+      }
-+
-+      for (i = 0; i < snd->nsubstreams; ++i) {
-+              struct virtio_pcm_stream *vs;
-+              struct virtio_pcm_substream *vss = &snd->substreams[i];
-+
-+              vpcm = virtsnd_pcm_find(snd, vss->nid);
-+              if (IS_ERR(vpcm))
-+                      return PTR_ERR(vpcm);
-+
-+              vs = &vpcm->streams[vss->direction];
-+              vs->substreams[vs->nsubstreams++] = vss;
-+      }
-+
-+      list_for_each_entry(vpcm, &snd->pcm_list, list) {
-+              for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) {
-+                      struct virtio_pcm_stream *vs = &vpcm->streams[i];
-+                      struct snd_pcm_str *ks = &vpcm->pcm->streams[i];
-+                      struct snd_pcm_substream *kss;
-+
-+                      if (!vs->nsubstreams)
-+                              continue;
-+
-+                      for (kss = ks->substream; kss; kss = kss->next)
-+                              vs->substreams[kss->number]->substream = kss;
-+              }
-+
-+              snd_pcm_set_managed_buffer_all(vpcm->pcm,
-+                                             SNDRV_DMA_TYPE_VMALLOC, NULL,
-+                                             0, 0);
-+      }
-+
-+      return 0;
-+}
-diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
-new file mode 100644
-index 000000000000..84f2f3f14f48
---- /dev/null
-+++ b/sound/virtio/virtio_pcm.h
-@@ -0,0 +1,72 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#ifndef VIRTIO_SND_PCM_H
-+#define VIRTIO_SND_PCM_H
-+
-+#include <linux/atomic.h>
-+#include <linux/virtio_config.h>
-+#include <sound/pcm.h>
-+
-+struct virtio_pcm;
-+struct virtio_pcm_msg;
-+
-+/**
-+ * struct virtio_pcm_substream - VirtIO PCM substream.
-+ * @snd: VirtIO sound device.
-+ * @nid: Function group node identifier.
-+ * @sid: Stream identifier.
-+ * @direction: Stream data flow direction (SNDRV_PCM_STREAM_XXX).
-+ * @features: Stream VirtIO feature bit map (1 << VIRTIO_SND_PCM_F_XXX).
-+ * @substream: Kernel ALSA substream.
-+ * @hw: Kernel ALSA substream hardware descriptor.
-+ * @elapsed_period: Kernel work to handle the elapsed period state.
-+ */
-+struct virtio_pcm_substream {
-+      struct virtio_snd *snd;
-+      u32 nid;
-+      u32 sid;
-+      u32 direction;
-+      u32 features;
-+      struct snd_pcm_substream *substream;
-+      struct snd_pcm_hardware hw;
-+      struct work_struct elapsed_period;
-+};
-+
-+/**
-+ * struct virtio_pcm_stream - VirtIO PCM stream.
-+ * @substreams: VirtIO substreams belonging to the stream.
-+ * @nsubstreams: Number of substreams.
-+ */
-+struct virtio_pcm_stream {
-+      struct virtio_pcm_substream **substreams;
-+      u32 nsubstreams;
-+};
-+
-+/**
-+ * struct virtio_pcm - VirtIO PCM device.
-+ * @list: VirtIO PCM list entry.
-+ * @nid: Function group node identifier.
-+ * @pcm: Kernel PCM device.
-+ * @streams: VirtIO PCM streams (playback and capture).
-+ */
-+struct virtio_pcm {
-+      struct list_head list;
-+      u32 nid;
-+      struct snd_pcm *pcm;
-+      struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1];
-+};
-+
-+int virtsnd_pcm_validate(struct virtio_device *vdev);
-+
-+int virtsnd_pcm_parse_cfg(struct virtio_snd *snd);
-+
-+int virtsnd_pcm_build_devs(struct virtio_snd *snd);
-+
-+struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid);
-+
-+struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid);
-+
-+#endif /* VIRTIO_SND_PCM_H */
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0005-ALSA-virtio-handling-control-and-I-O-messages-for-th.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0005-ALSA-virtio-handling-control-and-I-O-messages-for-th.patch
deleted file mode 100644 (file)
index 3a63a53..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-From e60175c8c7a51861c6f31af4cf99b95f3da7a59f Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:05 +0100
-Subject: [PATCH] ALSA: virtio: handling control and I/O messages for the PCM
- device
-
-The driver implements a message-based transport for I/O substream
-operations. Before the start of the substream, the hardware buffer is
-sliced into I/O messages, the number of which is equal to the current
-number of periods. The size of each message is equal to the current
-size of one period.
-
-I/O messages are organized in an ordered queue. The completion of the
-I/O message indicates an elapsed period (the only exception is the end
-of the stream for the capture substream). Upon completion, the message
-is automatically re-added to the end of the queue.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-6-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile         |   3 +-
- sound/virtio/virtio_card.c    |  22 +-
- sound/virtio/virtio_card.h    |   9 +
- sound/virtio/virtio_pcm.c     |  32 +++
- sound/virtio/virtio_pcm.h     |  40 ++++
- sound/virtio/virtio_pcm_msg.c | 414 ++++++++++++++++++++++++++++++++++
- 6 files changed, 515 insertions(+), 5 deletions(-)
- create mode 100644 sound/virtio/virtio_pcm_msg.c
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index 69162a545a41..626af3cc3ed7 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -5,5 +5,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
- virtio_snd-objs := \
-       virtio_card.o \
-       virtio_ctl_msg.o \
--      virtio_pcm.o
-+      virtio_pcm.o \
-+      virtio_pcm_msg.o
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index 11c76ee311b7..57b9b7f3a9c0 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -55,6 +55,12 @@ static void virtsnd_event_send(struct virtqueue *vqueue,
- static void virtsnd_event_dispatch(struct virtio_snd *snd,
-                                  struct virtio_snd_event *event)
- {
-+      switch (le32_to_cpu(event->hdr.code)) {
-+      case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
-+      case VIRTIO_SND_EVT_PCM_XRUN:
-+              virtsnd_pcm_event(snd, event);
-+              break;
-+      }
- }
- /**
-@@ -101,11 +107,15 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
-       struct virtio_device *vdev = snd->vdev;
-       static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
-               [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
--              [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
-+              [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb,
-+              [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb,
-+              [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb
-       };
-       static const char *names[VIRTIO_SND_VQ_MAX] = {
-               [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
--              [VIRTIO_SND_VQ_EVENT] = "virtsnd-event"
-+              [VIRTIO_SND_VQ_EVENT] = "virtsnd-event",
-+              [VIRTIO_SND_VQ_TX] = "virtsnd-tx",
-+              [VIRTIO_SND_VQ_RX] = "virtsnd-rx"
-       };
-       struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
-       unsigned int i;
-@@ -318,8 +328,12 @@ static void virtsnd_remove(struct virtio_device *vdev)
-       vdev->config->del_vqs(vdev);
-       vdev->config->reset(vdev);
--      for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
--              cancel_work_sync(&snd->substreams[i].elapsed_period);
-+      for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
-+              struct virtio_pcm_substream *vss = &snd->substreams[i];
-+
-+              cancel_work_sync(&vss->elapsed_period);
-+              virtsnd_pcm_msg_free(vss);
-+      }
-       kfree(snd->event_msgs);
- }
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-index 77a1b7255370..c43f9744d362 100644
---- a/sound/virtio/virtio_card.h
-+++ b/sound/virtio/virtio_card.h
-@@ -79,4 +79,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
-       return &snd->queues[VIRTIO_SND_VQ_RX];
- }
-+static inline struct virtio_snd_queue *
-+virtsnd_pcm_queue(struct virtio_pcm_substream *vss)
-+{
-+      if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK)
-+              return virtsnd_tx_queue(vss->snd);
-+      else
-+              return virtsnd_rx_queue(vss->snd);
-+}
-+
- #endif /* VIRTIO_SND_CARD_H */
-diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
-index e16567e2e214..2dcd763efa29 100644
---- a/sound/virtio/virtio_pcm.c
-+++ b/sound/virtio/virtio_pcm.c
-@@ -353,6 +353,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
-               vss->snd = snd;
-               vss->sid = i;
-               INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed);
-+              init_waitqueue_head(&vss->msg_empty);
-+              spin_lock_init(&vss->lock);
-               rc = virtsnd_pcm_build_hw(vss, &info[i]);
-               if (rc)
-@@ -477,3 +479,33 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd)
-       return 0;
- }
-+
-+/**
-+ * virtsnd_pcm_event() - Handle the PCM device event notification.
-+ * @snd: VirtIO sound device.
-+ * @event: VirtIO sound event.
-+ *
-+ * Context: Interrupt context.
-+ */
-+void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event)
-+{
-+      struct virtio_pcm_substream *vss;
-+      u32 sid = le32_to_cpu(event->data);
-+
-+      if (sid >= snd->nsubstreams)
-+              return;
-+
-+      vss = &snd->substreams[sid];
-+
-+      switch (le32_to_cpu(event->hdr.code)) {
-+      case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
-+              /* TODO: deal with shmem elapsed period */
-+              break;
-+      case VIRTIO_SND_EVT_PCM_XRUN:
-+              spin_lock(&vss->lock);
-+              if (vss->xfer_enabled)
-+                      vss->xfer_xrun = true;
-+              spin_unlock(&vss->lock);
-+              break;
-+      }
-+}
-diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
-index 84f2f3f14f48..6722f1139666 100644
---- a/sound/virtio/virtio_pcm.h
-+++ b/sound/virtio/virtio_pcm.h
-@@ -23,6 +23,17 @@ struct virtio_pcm_msg;
-  * @substream: Kernel ALSA substream.
-  * @hw: Kernel ALSA substream hardware descriptor.
-  * @elapsed_period: Kernel work to handle the elapsed period state.
-+ * @lock: Spinlock that protects fields shared by interrupt handlers and
-+ *        substream operators.
-+ * @buffer_bytes: Current buffer size in bytes.
-+ * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes).
-+ * @xfer_enabled: Data transfer state (0 - off, 1 - on).
-+ * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
-+ * @msgs: Allocated I/O messages.
-+ * @nmsgs: Number of allocated I/O messages.
-+ * @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
-+ * @msg_count: Number of pending I/O messages in the virtqueue.
-+ * @msg_empty: Notify when msg_count is zero.
-  */
- struct virtio_pcm_substream {
-       struct virtio_snd *snd;
-@@ -33,6 +44,16 @@ struct virtio_pcm_substream {
-       struct snd_pcm_substream *substream;
-       struct snd_pcm_hardware hw;
-       struct work_struct elapsed_period;
-+      spinlock_t lock;
-+      size_t buffer_bytes;
-+      size_t hw_ptr;
-+      bool xfer_enabled;
-+      bool xfer_xrun;
-+      struct virtio_pcm_msg **msgs;
-+      unsigned int nmsgs;
-+      int msg_last_enqueued;
-+      unsigned int msg_count;
-+      wait_queue_head_t msg_empty;
- };
- /**
-@@ -65,8 +86,27 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd);
- int virtsnd_pcm_build_devs(struct virtio_snd *snd);
-+void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event);
-+
-+void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue);
-+
-+void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue);
-+
- struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid);
- struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid);
-+struct virtio_snd_msg *
-+virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss,
-+                        unsigned int command, gfp_t gfp);
-+
-+int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss,
-+                        unsigned int periods, unsigned int period_bytes);
-+
-+void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss);
-+
-+int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss);
-+
-+unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss);
-+
- #endif /* VIRTIO_SND_PCM_H */
-diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c
-new file mode 100644
-index 000000000000..f88c8f29cbd8
---- /dev/null
-+++ b/sound/virtio/virtio_pcm_msg.c
-@@ -0,0 +1,414 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <sound/pcm_params.h>
-+
-+#include "virtio_card.h"
-+
-+/**
-+ * struct virtio_pcm_msg - VirtIO I/O message.
-+ * @substream: VirtIO PCM substream.
-+ * @xfer: Request header payload.
-+ * @status: Response header payload.
-+ * @length: Data length in bytes.
-+ * @sgs: Payload scatter-gather table.
-+ */
-+struct virtio_pcm_msg {
-+      struct virtio_pcm_substream *substream;
-+      struct virtio_snd_pcm_xfer xfer;
-+      struct virtio_snd_pcm_status status;
-+      size_t length;
-+      struct scatterlist sgs[0];
-+};
-+
-+/**
-+ * enum pcm_msg_sg_index - Index values for the virtio_pcm_msg->sgs field in
-+ *                         an I/O message.
-+ * @PCM_MSG_SG_XFER: Element containing a virtio_snd_pcm_xfer structure.
-+ * @PCM_MSG_SG_STATUS: Element containing a virtio_snd_pcm_status structure.
-+ * @PCM_MSG_SG_DATA: The first element containing a data buffer.
-+ */
-+enum pcm_msg_sg_index {
-+      PCM_MSG_SG_XFER = 0,
-+      PCM_MSG_SG_STATUS,
-+      PCM_MSG_SG_DATA
-+};
-+
-+/**
-+ * virtsnd_pcm_sg_num() - Count the number of sg-elements required to represent
-+ *                        vmalloc'ed buffer.
-+ * @data: Pointer to vmalloc'ed buffer.
-+ * @length: Buffer size.
-+ *
-+ * Context: Any context.
-+ * Return: Number of physically contiguous parts in the @data.
-+ */
-+static int virtsnd_pcm_sg_num(u8 *data, unsigned int length)
-+{
-+      phys_addr_t sg_address;
-+      unsigned int sg_length;
-+      int num = 0;
-+
-+      while (length) {
-+              struct page *pg = vmalloc_to_page(data);
-+              phys_addr_t pg_address = page_to_phys(pg);
-+              size_t pg_length;
-+
-+              pg_length = PAGE_SIZE - offset_in_page(data);
-+              if (pg_length > length)
-+                      pg_length = length;
-+
-+              if (!num || sg_address + sg_length != pg_address) {
-+                      sg_address = pg_address;
-+                      sg_length = pg_length;
-+                      num++;
-+              } else {
-+                      sg_length += pg_length;
-+              }
-+
-+              data += pg_length;
-+              length -= pg_length;
-+      }
-+
-+      return num;
-+}
-+
-+/**
-+ * virtsnd_pcm_sg_from() - Build sg-list from vmalloc'ed buffer.
-+ * @sgs: Preallocated sg-list to populate.
-+ * @nsgs: The maximum number of elements in the @sgs.
-+ * @data: Pointer to vmalloc'ed buffer.
-+ * @length: Buffer size.
-+ *
-+ * Splits the buffer into physically contiguous parts and makes an sg-list of
-+ * such parts.
-+ *
-+ * Context: Any context.
-+ */
-+static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data,
-+                              unsigned int length)
-+{
-+      int idx = -1;
-+
-+      while (length) {
-+              struct page *pg = vmalloc_to_page(data);
-+              size_t pg_length;
-+
-+              pg_length = PAGE_SIZE - offset_in_page(data);
-+              if (pg_length > length)
-+                      pg_length = length;
-+
-+              if (idx == -1 ||
-+                  sg_phys(&sgs[idx]) + sgs[idx].length != page_to_phys(pg)) {
-+                      if (idx + 1 == nsgs)
-+                              break;
-+                      sg_set_page(&sgs[++idx], pg, pg_length,
-+                                  offset_in_page(data));
-+              } else {
-+                      sgs[idx].length += pg_length;
-+              }
-+
-+              data += pg_length;
-+              length -= pg_length;
-+      }
-+
-+      sg_mark_end(&sgs[idx]);
-+}
-+
-+/**
-+ * virtsnd_pcm_msg_alloc() - Allocate I/O messages.
-+ * @vss: VirtIO PCM substream.
-+ * @periods: Current number of periods.
-+ * @period_bytes: Current period size in bytes.
-+ *
-+ * The function slices the buffer into @periods parts (each with the size of
-+ * @period_bytes), and creates @periods corresponding I/O messages.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -ENOMEM on failure.
-+ */
-+int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss,
-+                        unsigned int periods, unsigned int period_bytes)
-+{
-+      struct snd_pcm_runtime *runtime = vss->substream->runtime;
-+      unsigned int i;
-+
-+      vss->msgs = kcalloc(periods, sizeof(*vss->msgs), GFP_KERNEL);
-+      if (!vss->msgs)
-+              return -ENOMEM;
-+
-+      vss->nmsgs = periods;
-+
-+      for (i = 0; i < periods; ++i) {
-+              u8 *data = runtime->dma_area + period_bytes * i;
-+              int sg_num = virtsnd_pcm_sg_num(data, period_bytes);
-+              struct virtio_pcm_msg *msg;
-+
-+              msg = kzalloc(sizeof(*msg) + sizeof(*msg->sgs) * (sg_num + 2),
-+                            GFP_KERNEL);
-+              if (!msg)
-+                      return -ENOMEM;
-+
-+              msg->substream = vss;
-+              sg_init_one(&msg->sgs[PCM_MSG_SG_XFER], &msg->xfer,
-+                          sizeof(msg->xfer));
-+              sg_init_one(&msg->sgs[PCM_MSG_SG_STATUS], &msg->status,
-+                          sizeof(msg->status));
-+              msg->length = period_bytes;
-+              virtsnd_pcm_sg_from(&msg->sgs[PCM_MSG_SG_DATA], sg_num, data,
-+                                  period_bytes);
-+
-+              vss->msgs[i] = msg;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_msg_free() - Free all allocated I/O messages.
-+ * @vss: VirtIO PCM substream.
-+ *
-+ * Context: Any context.
-+ */
-+void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss)
-+{
-+      unsigned int i;
-+
-+      for (i = 0; vss->msgs && i < vss->nmsgs; ++i)
-+              kfree(vss->msgs[i]);
-+      kfree(vss->msgs);
-+
-+      vss->msgs = NULL;
-+      vss->nmsgs = 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_msg_send() - Send asynchronous I/O messages.
-+ * @vss: VirtIO PCM substream.
-+ *
-+ * All messages are organized in an ordered circular list. Each time the
-+ * function is called, all currently non-enqueued messages are added to the
-+ * virtqueue. For this, the function keeps track of two values:
-+ *
-+ *   msg_last_enqueued = index of the last enqueued message,
-+ *   msg_count = # of pending messages in the virtqueue.
-+ *
-+ * Context: Any context. Expects the tx/rx queue and the VirtIO substream
-+ *          spinlocks to be held by caller.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss)
-+{
-+      struct snd_pcm_runtime *runtime = vss->substream->runtime;
-+      struct virtio_snd *snd = vss->snd;
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtqueue *vqueue = virtsnd_pcm_queue(vss)->vqueue;
-+      int i;
-+      int n;
-+      bool notify = false;
-+
-+      i = (vss->msg_last_enqueued + 1) % runtime->periods;
-+      n = runtime->periods - vss->msg_count;
-+
-+      for (; n; --n, i = (i + 1) % runtime->periods) {
-+              struct virtio_pcm_msg *msg = vss->msgs[i];
-+              struct scatterlist *psgs[] = {
-+                      &msg->sgs[PCM_MSG_SG_XFER],
-+                      &msg->sgs[PCM_MSG_SG_DATA],
-+                      &msg->sgs[PCM_MSG_SG_STATUS]
-+              };
-+              int rc;
-+
-+              msg->xfer.stream_id = cpu_to_le32(vss->sid);
-+              memset(&msg->status, 0, sizeof(msg->status));
-+
-+              if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK)
-+                      rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg,
-+                                             GFP_ATOMIC);
-+              else
-+                      rc = virtqueue_add_sgs(vqueue, psgs, 1, 2, msg,
-+                                             GFP_ATOMIC);
-+
-+              if (rc) {
-+                      dev_err(&vdev->dev,
-+                              "SID %u: failed to send I/O message\n",
-+                              vss->sid);
-+                      return rc;
-+              }
-+
-+              vss->msg_last_enqueued = i;
-+              vss->msg_count++;
-+      }
-+
-+      if (!(vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING)))
-+              notify = virtqueue_kick_prepare(vqueue);
-+
-+      if (notify)
-+              virtqueue_notify(vqueue);
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_msg_pending_num() - Returns the number of pending I/O messages.
-+ * @vss: VirtIO substream.
-+ *
-+ * Context: Any context.
-+ * Return: Number of messages.
-+ */
-+unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss)
-+{
-+      unsigned int num;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&vss->lock, flags);
-+      num = vss->msg_count;
-+      spin_unlock_irqrestore(&vss->lock, flags);
-+
-+      return num;
-+}
-+
-+/**
-+ * virtsnd_pcm_msg_complete() - Complete an I/O message.
-+ * @msg: I/O message.
-+ * @written_bytes: Number of bytes written to the message.
-+ *
-+ * Completion of the message means the elapsed period. If transmission is
-+ * allowed, then each completed message is immediately placed back at the end
-+ * of the queue.
-+ *
-+ * For the playback substream, @written_bytes is equal to sizeof(msg->status).
-+ *
-+ * For the capture substream, @written_bytes is equal to sizeof(msg->status)
-+ * plus the number of captured bytes.
-+ *
-+ * Context: Interrupt context. Takes and releases the VirtIO substream spinlock.
-+ */
-+static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg,
-+                                   size_t written_bytes)
-+{
-+      struct virtio_pcm_substream *vss = msg->substream;
-+
-+      /*
-+       * hw_ptr always indicates the buffer position of the first I/O message
-+       * in the virtqueue. Therefore, on each completion of an I/O message,
-+       * the hw_ptr value is unconditionally advanced.
-+       */
-+      spin_lock(&vss->lock);
-+      /*
-+       * If the capture substream returned an incorrect status, then just
-+       * increase the hw_ptr by the message size.
-+       */
-+      if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK ||
-+          written_bytes <= sizeof(msg->status))
-+              vss->hw_ptr += msg->length;
-+      else
-+              vss->hw_ptr += written_bytes - sizeof(msg->status);
-+
-+      if (vss->hw_ptr >= vss->buffer_bytes)
-+              vss->hw_ptr -= vss->buffer_bytes;
-+
-+      vss->xfer_xrun = false;
-+      vss->msg_count--;
-+
-+      if (vss->xfer_enabled) {
-+              struct snd_pcm_runtime *runtime = vss->substream->runtime;
-+
-+              runtime->delay =
-+                      bytes_to_frames(runtime,
-+                                      le32_to_cpu(msg->status.latency_bytes));
-+
-+              schedule_work(&vss->elapsed_period);
-+
-+              virtsnd_pcm_msg_send(vss);
-+      } else if (!vss->msg_count) {
-+              wake_up_all(&vss->msg_empty);
-+      }
-+      spin_unlock(&vss->lock);
-+}
-+
-+/**
-+ * virtsnd_pcm_notify_cb() - Process all completed I/O messages.
-+ * @queue: Underlying tx/rx virtqueue.
-+ *
-+ * Context: Interrupt context. Takes and releases the tx/rx queue spinlock.
-+ */
-+static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue)
-+{
-+      struct virtio_pcm_msg *msg;
-+      u32 written_bytes;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&queue->lock, flags);
-+      do {
-+              virtqueue_disable_cb(queue->vqueue);
-+              while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes)))
-+                      virtsnd_pcm_msg_complete(msg, written_bytes);
-+              if (unlikely(virtqueue_is_broken(queue->vqueue)))
-+                      break;
-+      } while (!virtqueue_enable_cb(queue->vqueue));
-+      spin_unlock_irqrestore(&queue->lock, flags);
-+}
-+
-+/**
-+ * virtsnd_pcm_tx_notify_cb() - Process all completed TX messages.
-+ * @vqueue: Underlying tx virtqueue.
-+ *
-+ * Context: Interrupt context.
-+ */
-+void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue)
-+{
-+      struct virtio_snd *snd = vqueue->vdev->priv;
-+
-+      virtsnd_pcm_notify_cb(virtsnd_tx_queue(snd));
-+}
-+
-+/**
-+ * virtsnd_pcm_rx_notify_cb() - Process all completed RX messages.
-+ * @vqueue: Underlying rx virtqueue.
-+ *
-+ * Context: Interrupt context.
-+ */
-+void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue)
-+{
-+      struct virtio_snd *snd = vqueue->vdev->priv;
-+
-+      virtsnd_pcm_notify_cb(virtsnd_rx_queue(snd));
-+}
-+
-+/**
-+ * virtsnd_pcm_ctl_msg_alloc() - Allocate and initialize the PCM device control
-+ *                               message for the specified substream.
-+ * @vss: VirtIO PCM substream.
-+ * @command: Control request code (VIRTIO_SND_R_PCM_XXX).
-+ * @gfp: Kernel flags for memory allocation.
-+ *
-+ * Context: Any context. May sleep if @gfp flags permit.
-+ * Return: Allocated message on success, NULL on failure.
-+ */
-+struct virtio_snd_msg *
-+virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss,
-+                        unsigned int command, gfp_t gfp)
-+{
-+      size_t request_size = sizeof(struct virtio_snd_pcm_hdr);
-+      size_t response_size = sizeof(struct virtio_snd_hdr);
-+      struct virtio_snd_msg *msg;
-+
-+      switch (command) {
-+      case VIRTIO_SND_R_PCM_SET_PARAMS:
-+              request_size = sizeof(struct virtio_snd_pcm_set_params);
-+              break;
-+      }
-+
-+      msg = virtsnd_ctl_msg_alloc(request_size, response_size, gfp);
-+      if (msg) {
-+              struct virtio_snd_pcm_hdr *hdr = virtsnd_ctl_msg_request(msg);
-+
-+              hdr->hdr.code = cpu_to_le32(command);
-+              hdr->stream_id = cpu_to_le32(vss->sid);
-+      }
-+
-+      return msg;
-+}
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0006-ALSA-virtio-PCM-substream-operators.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0006-ALSA-virtio-PCM-substream-operators.patch
deleted file mode 100644 (file)
index 9196b34..0000000
+++ /dev/null
@@ -1,525 +0,0 @@
-From 93c313dc4fc78b077bb0911afe3a77ffa845ad58 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:06 +0100
-Subject: [PATCH] ALSA: virtio: PCM substream operators
-
-Introduce the operators required for the operation of substreams.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-7-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile         |   3 +-
- sound/virtio/virtio_pcm.c     |   2 +
- sound/virtio/virtio_pcm.h     |   5 +
- sound/virtio/virtio_pcm_ops.c | 445 ++++++++++++++++++++++++++++++++++
- 4 files changed, 454 insertions(+), 1 deletion(-)
- create mode 100644 sound/virtio/virtio_pcm_ops.c
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index 626af3cc3ed7..34493226793f 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -6,5 +6,6 @@ virtio_snd-objs := \
-       virtio_card.o \
-       virtio_ctl_msg.o \
-       virtio_pcm.o \
--      virtio_pcm_msg.o
-+      virtio_pcm_msg.o \
-+      virtio_pcm_ops.o
-diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
-index 2dcd763efa29..c10d91fff2fb 100644
---- a/sound/virtio/virtio_pcm.c
-+++ b/sound/virtio/virtio_pcm.c
-@@ -470,6 +470,8 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd)
-                       for (kss = ks->substream; kss; kss = kss->next)
-                               vs->substreams[kss->number]->substream = kss;
-+
-+                      snd_pcm_set_ops(vpcm->pcm, i, &virtsnd_pcm_ops);
-               }
-               snd_pcm_set_managed_buffer_all(vpcm->pcm,
-diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
-index 6722f1139666..efd0228746cf 100644
---- a/sound/virtio/virtio_pcm.h
-+++ b/sound/virtio/virtio_pcm.h
-@@ -29,6 +29,8 @@ struct virtio_pcm_msg;
-  * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes).
-  * @xfer_enabled: Data transfer state (0 - off, 1 - on).
-  * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
-+ * @stopped: True if the substream is stopped and must be released on the device
-+ *           side.
-  * @msgs: Allocated I/O messages.
-  * @nmsgs: Number of allocated I/O messages.
-  * @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
-@@ -49,6 +51,7 @@ struct virtio_pcm_substream {
-       size_t hw_ptr;
-       bool xfer_enabled;
-       bool xfer_xrun;
-+      bool stopped;
-       struct virtio_pcm_msg **msgs;
-       unsigned int nmsgs;
-       int msg_last_enqueued;
-@@ -80,6 +83,8 @@ struct virtio_pcm {
-       struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1];
- };
-+extern const struct snd_pcm_ops virtsnd_pcm_ops;
-+
- int virtsnd_pcm_validate(struct virtio_device *vdev);
- int virtsnd_pcm_parse_cfg(struct virtio_snd *snd);
-diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
-new file mode 100644
-index 000000000000..0682a2df6c8c
---- /dev/null
-+++ b/sound/virtio/virtio_pcm_ops.c
-@@ -0,0 +1,445 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <sound/pcm_params.h>
-+
-+#include "virtio_card.h"
-+
-+/*
-+ * I/O messages lifetime
-+ * ---------------------
-+ *
-+ * Allocation:
-+ *   Messages are initially allocated in the ops->hw_params() after the size and
-+ *   number of periods have been successfully negotiated.
-+ *
-+ * Freeing:
-+ *   Messages can be safely freed after the queue has been successfully flushed
-+ *   (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been
-+ *   called.
-+ *
-+ *   When the substream stops, the ops->sync_stop() waits until the device has
-+ *   completed all pending messages. This wait can be interrupted either by a
-+ *   signal or due to a timeout. In this case, the device can still access
-+ *   messages even after calling ops->hw_free(). It can also issue an interrupt,
-+ *   and the interrupt handler will also try to access message structures.
-+ *
-+ *   Therefore, freeing of already allocated messages occurs:
-+ *
-+ *   - in ops->hw_params(), if this operator was called several times in a row,
-+ *     or if ops->hw_free() failed to free messages previously;
-+ *
-+ *   - in ops->hw_free(), if the queue has been successfully flushed;
-+ *
-+ *   - in dev->release().
-+ */
-+
-+/* Map for converting ALSA format to VirtIO format. */
-+struct virtsnd_a2v_format {
-+      snd_pcm_format_t alsa_bit;
-+      unsigned int vio_bit;
-+};
-+
-+static const struct virtsnd_a2v_format g_a2v_format_map[] = {
-+      { SNDRV_PCM_FORMAT_IMA_ADPCM, VIRTIO_SND_PCM_FMT_IMA_ADPCM },
-+      { SNDRV_PCM_FORMAT_MU_LAW, VIRTIO_SND_PCM_FMT_MU_LAW },
-+      { SNDRV_PCM_FORMAT_A_LAW, VIRTIO_SND_PCM_FMT_A_LAW },
-+      { SNDRV_PCM_FORMAT_S8, VIRTIO_SND_PCM_FMT_S8 },
-+      { SNDRV_PCM_FORMAT_U8, VIRTIO_SND_PCM_FMT_U8 },
-+      { SNDRV_PCM_FORMAT_S16_LE, VIRTIO_SND_PCM_FMT_S16 },
-+      { SNDRV_PCM_FORMAT_U16_LE, VIRTIO_SND_PCM_FMT_U16 },
-+      { SNDRV_PCM_FORMAT_S18_3LE, VIRTIO_SND_PCM_FMT_S18_3 },
-+      { SNDRV_PCM_FORMAT_U18_3LE, VIRTIO_SND_PCM_FMT_U18_3 },
-+      { SNDRV_PCM_FORMAT_S20_3LE, VIRTIO_SND_PCM_FMT_S20_3 },
-+      { SNDRV_PCM_FORMAT_U20_3LE, VIRTIO_SND_PCM_FMT_U20_3 },
-+      { SNDRV_PCM_FORMAT_S24_3LE, VIRTIO_SND_PCM_FMT_S24_3 },
-+      { SNDRV_PCM_FORMAT_U24_3LE, VIRTIO_SND_PCM_FMT_U24_3 },
-+      { SNDRV_PCM_FORMAT_S20_LE, VIRTIO_SND_PCM_FMT_S20 },
-+      { SNDRV_PCM_FORMAT_U20_LE, VIRTIO_SND_PCM_FMT_U20 },
-+      { SNDRV_PCM_FORMAT_S24_LE, VIRTIO_SND_PCM_FMT_S24 },
-+      { SNDRV_PCM_FORMAT_U24_LE, VIRTIO_SND_PCM_FMT_U24 },
-+      { SNDRV_PCM_FORMAT_S32_LE, VIRTIO_SND_PCM_FMT_S32 },
-+      { SNDRV_PCM_FORMAT_U32_LE, VIRTIO_SND_PCM_FMT_U32 },
-+      { SNDRV_PCM_FORMAT_FLOAT_LE, VIRTIO_SND_PCM_FMT_FLOAT },
-+      { SNDRV_PCM_FORMAT_FLOAT64_LE, VIRTIO_SND_PCM_FMT_FLOAT64 },
-+      { SNDRV_PCM_FORMAT_DSD_U8, VIRTIO_SND_PCM_FMT_DSD_U8 },
-+      { SNDRV_PCM_FORMAT_DSD_U16_LE, VIRTIO_SND_PCM_FMT_DSD_U16 },
-+      { SNDRV_PCM_FORMAT_DSD_U32_LE, VIRTIO_SND_PCM_FMT_DSD_U32 },
-+      { SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE,
-+        VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME }
-+};
-+
-+/* Map for converting ALSA frame rate to VirtIO frame rate. */
-+struct virtsnd_a2v_rate {
-+      unsigned int rate;
-+      unsigned int vio_bit;
-+};
-+
-+static const struct virtsnd_a2v_rate g_a2v_rate_map[] = {
-+      { 5512, VIRTIO_SND_PCM_RATE_5512 },
-+      { 8000, VIRTIO_SND_PCM_RATE_8000 },
-+      { 11025, VIRTIO_SND_PCM_RATE_11025 },
-+      { 16000, VIRTIO_SND_PCM_RATE_16000 },
-+      { 22050, VIRTIO_SND_PCM_RATE_22050 },
-+      { 32000, VIRTIO_SND_PCM_RATE_32000 },
-+      { 44100, VIRTIO_SND_PCM_RATE_44100 },
-+      { 48000, VIRTIO_SND_PCM_RATE_48000 },
-+      { 64000, VIRTIO_SND_PCM_RATE_64000 },
-+      { 88200, VIRTIO_SND_PCM_RATE_88200 },
-+      { 96000, VIRTIO_SND_PCM_RATE_96000 },
-+      { 176400, VIRTIO_SND_PCM_RATE_176400 },
-+      { 192000, VIRTIO_SND_PCM_RATE_192000 }
-+};
-+
-+static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream);
-+
-+/**
-+ * virtsnd_pcm_open() - Open the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * Context: Process context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
-+{
-+      struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream);
-+      struct virtio_pcm_stream *vs = &vpcm->streams[substream->stream];
-+      struct virtio_pcm_substream *vss = vs->substreams[substream->number];
-+
-+      substream->runtime->hw = vss->hw;
-+      substream->private_data = vss;
-+
-+      snd_pcm_hw_constraint_integer(substream->runtime,
-+                                    SNDRV_PCM_HW_PARAM_PERIODS);
-+
-+      vss->stopped = !!virtsnd_pcm_msg_pending_num(vss);
-+
-+      /*
-+       * If the substream has already been used, then the I/O queue may be in
-+       * an invalid state. Just in case, we do a check and try to return the
-+       * queue to its original state, if necessary.
-+       */
-+      return virtsnd_pcm_sync_stop(substream);
-+}
-+
-+/**
-+ * virtsnd_pcm_close() - Close the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * Context: Process context.
-+ * Return: 0.
-+ */
-+static int virtsnd_pcm_close(struct snd_pcm_substream *substream)
-+{
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_dev_set_params() - Set the parameters of the PCM substream on
-+ *                                the device side.
-+ * @vss: VirtIO PCM substream.
-+ * @buffer_bytes: Size of the hardware buffer.
-+ * @period_bytes: Size of the hardware period.
-+ * @channels: Selected number of channels.
-+ * @format: Selected sample format (SNDRV_PCM_FORMAT_XXX).
-+ * @rate: Selected frame rate.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_dev_set_params(struct virtio_pcm_substream *vss,
-+                                    unsigned int buffer_bytes,
-+                                    unsigned int period_bytes,
-+                                    unsigned int channels,
-+                                    snd_pcm_format_t format,
-+                                    unsigned int rate)
-+{
-+      struct virtio_snd_msg *msg;
-+      struct virtio_snd_pcm_set_params *request;
-+      unsigned int i;
-+      int vformat = -1;
-+      int vrate = -1;
-+
-+      for (i = 0; i < ARRAY_SIZE(g_a2v_format_map); ++i)
-+              if (g_a2v_format_map[i].alsa_bit == format) {
-+                      vformat = g_a2v_format_map[i].vio_bit;
-+
-+                      break;
-+              }
-+
-+      for (i = 0; i < ARRAY_SIZE(g_a2v_rate_map); ++i)
-+              if (g_a2v_rate_map[i].rate == rate) {
-+                      vrate = g_a2v_rate_map[i].vio_bit;
-+
-+                      break;
-+              }
-+
-+      if (vformat == -1 || vrate == -1)
-+              return -EINVAL;
-+
-+      msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_SET_PARAMS,
-+                                      GFP_KERNEL);
-+      if (!msg)
-+              return -ENOMEM;
-+
-+      request = virtsnd_ctl_msg_request(msg);
-+      request->buffer_bytes = cpu_to_le32(buffer_bytes);
-+      request->period_bytes = cpu_to_le32(period_bytes);
-+      request->channels = channels;
-+      request->format = vformat;
-+      request->rate = vrate;
-+
-+      if (vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING))
-+              request->features |=
-+                      cpu_to_le32(1U << VIRTIO_SND_PCM_F_MSG_POLLING);
-+
-+      if (vss->features & (1U << VIRTIO_SND_PCM_F_EVT_XRUNS))
-+              request->features |=
-+                      cpu_to_le32(1U << VIRTIO_SND_PCM_F_EVT_XRUNS);
-+
-+      return virtsnd_ctl_msg_send_sync(vss->snd, msg);
-+}
-+
-+/**
-+ * virtsnd_pcm_hw_params() - Set the parameters of the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ * @hw_params: Hardware parameters.
-+ *
-+ * Context: Process context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream,
-+                               struct snd_pcm_hw_params *hw_params)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+      struct virtio_device *vdev = vss->snd->vdev;
-+      int rc;
-+
-+      if (virtsnd_pcm_msg_pending_num(vss)) {
-+              dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
-+                      vss->sid);
-+              return -EBADFD;
-+      }
-+
-+      rc = virtsnd_pcm_dev_set_params(vss, params_buffer_bytes(hw_params),
-+                                      params_period_bytes(hw_params),
-+                                      params_channels(hw_params),
-+                                      params_format(hw_params),
-+                                      params_rate(hw_params));
-+      if (rc)
-+              return rc;
-+
-+      /*
-+       * Free previously allocated messages if ops->hw_params() is called
-+       * several times in a row, or if ops->hw_free() failed to free messages.
-+       */
-+      virtsnd_pcm_msg_free(vss);
-+
-+      return virtsnd_pcm_msg_alloc(vss, params_periods(hw_params),
-+                                   params_period_bytes(hw_params));
-+}
-+
-+/**
-+ * virtsnd_pcm_hw_free() - Reset the parameters of the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * Context: Process context.
-+ * Return: 0
-+ */
-+static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+
-+      /* If the queue is flushed, we can safely free the messages here. */
-+      if (!virtsnd_pcm_msg_pending_num(vss))
-+              virtsnd_pcm_msg_free(vss);
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_prepare() - Prepare the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * Context: Process context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+      struct virtio_device *vdev = vss->snd->vdev;
-+      struct virtio_snd_msg *msg;
-+
-+      if (virtsnd_pcm_msg_pending_num(vss)) {
-+              dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
-+                      vss->sid);
-+              return -EBADFD;
-+      }
-+
-+      vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-+      vss->hw_ptr = 0;
-+      vss->xfer_xrun = false;
-+      vss->msg_last_enqueued = -1;
-+      vss->msg_count = 0;
-+
-+      msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE,
-+                                      GFP_KERNEL);
-+      if (!msg)
-+              return -ENOMEM;
-+
-+      return virtsnd_ctl_msg_send_sync(vss->snd, msg);
-+}
-+
-+/**
-+ * virtsnd_pcm_trigger() - Process command for the PCM substream.
-+ * @substream: Kernel ALSA substream.
-+ * @command: Substream command (SNDRV_PCM_TRIGGER_XXX).
-+ *
-+ * Context: Any context. Takes and releases the VirtIO substream spinlock.
-+ *          May take and release the tx/rx queue spinlock.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+      struct virtio_snd *snd = vss->snd;
-+      struct virtio_snd_queue *queue;
-+      struct virtio_snd_msg *msg;
-+      unsigned long flags;
-+      int rc;
-+
-+      switch (command) {
-+      case SNDRV_PCM_TRIGGER_START:
-+      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+              queue = virtsnd_pcm_queue(vss);
-+
-+              spin_lock_irqsave(&queue->lock, flags);
-+              spin_lock(&vss->lock);
-+              rc = virtsnd_pcm_msg_send(vss);
-+              if (!rc)
-+                      vss->xfer_enabled = true;
-+              spin_unlock(&vss->lock);
-+              spin_unlock_irqrestore(&queue->lock, flags);
-+              if (rc)
-+                      return rc;
-+
-+              msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START,
-+                                              GFP_KERNEL);
-+              if (!msg) {
-+                      spin_lock_irqsave(&vss->lock, flags);
-+                      vss->xfer_enabled = false;
-+                      spin_unlock_irqrestore(&vss->lock, flags);
-+
-+                      return -ENOMEM;
-+              }
-+
-+              return virtsnd_ctl_msg_send_sync(snd, msg);
-+      case SNDRV_PCM_TRIGGER_STOP:
-+              vss->stopped = true;
-+              fallthrough;
-+      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+              spin_lock_irqsave(&vss->lock, flags);
-+              vss->xfer_enabled = false;
-+              spin_unlock_irqrestore(&vss->lock, flags);
-+
-+              msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP,
-+                                              GFP_KERNEL);
-+              if (!msg)
-+                      return -ENOMEM;
-+
-+              return virtsnd_ctl_msg_send_sync(snd, msg);
-+      default:
-+              return -EINVAL;
-+      }
-+}
-+
-+/**
-+ * virtsnd_pcm_sync_stop() - Synchronous PCM substream stop.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * The function can be called both from the upper level or from the driver
-+ * itself.
-+ *
-+ * Context: Process context. Takes and releases the VirtIO substream spinlock.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+      struct virtio_snd *snd = vss->snd;
-+      struct virtio_snd_msg *msg;
-+      unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
-+      int rc;
-+
-+      cancel_work_sync(&vss->elapsed_period);
-+
-+      if (!vss->stopped)
-+              return 0;
-+
-+      msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE,
-+                                      GFP_KERNEL);
-+      if (!msg)
-+              return -ENOMEM;
-+
-+      rc = virtsnd_ctl_msg_send_sync(snd, msg);
-+      if (rc)
-+              return rc;
-+
-+      /*
-+       * The spec states that upon receipt of the RELEASE command "the device
-+       * MUST complete all pending I/O messages for the specified stream ID".
-+       * Thus, we consider the absence of I/O messages in the queue as an
-+       * indication that the substream has been released.
-+       */
-+      rc = wait_event_interruptible_timeout(vss->msg_empty,
-+                                            !virtsnd_pcm_msg_pending_num(vss),
-+                                            js);
-+      if (rc <= 0) {
-+              dev_warn(&snd->vdev->dev, "SID %u: failed to flush I/O queue\n",
-+                       vss->sid);
-+
-+              return !rc ? -ETIMEDOUT : rc;
-+      }
-+
-+      vss->stopped = false;
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_pcm_pointer() - Get the current hardware position for the PCM
-+ *                         substream.
-+ * @substream: Kernel ALSA substream.
-+ *
-+ * Context: Any context. Takes and releases the VirtIO substream spinlock.
-+ * Return: Hardware position in frames inside [0 ... buffer_size) range.
-+ */
-+static snd_pcm_uframes_t
-+virtsnd_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+      struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
-+      snd_pcm_uframes_t hw_ptr = SNDRV_PCM_POS_XRUN;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&vss->lock, flags);
-+      if (!vss->xfer_xrun)
-+              hw_ptr = bytes_to_frames(substream->runtime, vss->hw_ptr);
-+      spin_unlock_irqrestore(&vss->lock, flags);
-+
-+      return hw_ptr;
-+}
-+
-+/* PCM substream operators map. */
-+const struct snd_pcm_ops virtsnd_pcm_ops = {
-+      .open = virtsnd_pcm_open,
-+      .close = virtsnd_pcm_close,
-+      .ioctl = snd_pcm_lib_ioctl,
-+      .hw_params = virtsnd_pcm_hw_params,
-+      .hw_free = virtsnd_pcm_hw_free,
-+      .prepare = virtsnd_pcm_prepare,
-+      .trigger = virtsnd_pcm_trigger,
-+      .sync_stop = virtsnd_pcm_sync_stop,
-+      .pointer = virtsnd_pcm_pointer,
-+};
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0007-ALSA-virtio-introduce-jack-support.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0007-ALSA-virtio-introduce-jack-support.patch
deleted file mode 100644 (file)
index af30421..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-From 07692f250a96382b38daa2b7e2b96689f64d7a40 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:07 +0100
-Subject: [PATCH] ALSA: virtio: introduce jack support
-
-Enumerate all available jacks and create ALSA controls.
-
-At the moment jacks have a simple implementation and can only be used
-to receive notifications about a plugged in/out device.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-8-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile      |   1 +
- sound/virtio/virtio_card.c |  14 +++
- sound/virtio/virtio_card.h |  12 ++
- sound/virtio/virtio_jack.c | 233 +++++++++++++++++++++++++++++++++++++
- 4 files changed, 260 insertions(+)
- create mode 100644 sound/virtio/virtio_jack.c
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index 34493226793f..09f485291285 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -5,6 +5,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
- virtio_snd-objs := \
-       virtio_card.o \
-       virtio_ctl_msg.o \
-+      virtio_jack.o \
-       virtio_pcm.o \
-       virtio_pcm_msg.o \
-       virtio_pcm_ops.o
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index 57b9b7f3a9c0..89bd66c1256e 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -56,6 +56,10 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd,
-                                  struct virtio_snd_event *event)
- {
-       switch (le32_to_cpu(event->hdr.code)) {
-+      case VIRTIO_SND_EVT_JACK_CONNECTED:
-+      case VIRTIO_SND_EVT_JACK_DISCONNECTED:
-+              virtsnd_jack_event(snd, event);
-+              break;
-       case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
-       case VIRTIO_SND_EVT_PCM_XRUN:
-               virtsnd_pcm_event(snd, event);
-@@ -219,10 +223,20 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
-                        VIRTIO_SND_CARD_NAME " at %s/%s",
-                        dev_name(dev->parent), dev_name(dev));
-+      rc = virtsnd_jack_parse_cfg(snd);
-+      if (rc)
-+              return rc;
-+
-       rc = virtsnd_pcm_parse_cfg(snd);
-       if (rc)
-               return rc;
-+      if (snd->njacks) {
-+              rc = virtsnd_jack_build_devs(snd);
-+              if (rc)
-+                      return rc;
-+      }
-+
-       if (snd->nsubstreams) {
-               rc = virtsnd_pcm_build_devs(snd);
-               if (rc)
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-index c43f9744d362..f154313c79fd 100644
---- a/sound/virtio/virtio_card.h
-+++ b/sound/virtio/virtio_card.h
-@@ -18,6 +18,7 @@
- #define VIRTIO_SND_CARD_NAME  "VirtIO SoundCard"
- #define VIRTIO_SND_PCM_NAME   "VirtIO PCM"
-+struct virtio_jack;
- struct virtio_pcm_substream;
- /**
-@@ -38,6 +39,8 @@ struct virtio_snd_queue {
-  * @ctl_msgs: Pending control request list.
-  * @event_msgs: Device events.
-  * @pcm_list: VirtIO PCM device list.
-+ * @jacks: VirtIO jacks.
-+ * @njacks: Number of jacks.
-  * @substreams: VirtIO PCM substreams.
-  * @nsubstreams: Number of PCM substreams.
-  */
-@@ -48,6 +51,8 @@ struct virtio_snd {
-       struct list_head ctl_msgs;
-       struct virtio_snd_event *event_msgs;
-       struct list_head pcm_list;
-+      struct virtio_jack *jacks;
-+      u32 njacks;
-       struct virtio_pcm_substream *substreams;
-       u32 nsubstreams;
- };
-@@ -88,4 +93,11 @@ virtsnd_pcm_queue(struct virtio_pcm_substream *vss)
-               return virtsnd_rx_queue(vss->snd);
- }
-+int virtsnd_jack_parse_cfg(struct virtio_snd *snd);
-+
-+int virtsnd_jack_build_devs(struct virtio_snd *snd);
-+
-+void virtsnd_jack_event(struct virtio_snd *snd,
-+                      struct virtio_snd_event *event);
-+
- #endif /* VIRTIO_SND_CARD_H */
-diff --git a/sound/virtio/virtio_jack.c b/sound/virtio/virtio_jack.c
-new file mode 100644
-index 000000000000..c69f1dcdcc84
---- /dev/null
-+++ b/sound/virtio/virtio_jack.c
-@@ -0,0 +1,233 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <linux/virtio_config.h>
-+#include <sound/jack.h>
-+#include <sound/hda_verbs.h>
-+
-+#include "virtio_card.h"
-+
-+/**
-+ * DOC: Implementation Status
-+ *
-+ * At the moment jacks have a simple implementation and can only be used to
-+ * receive notifications about a plugged in/out device.
-+ *
-+ * VIRTIO_SND_R_JACK_REMAP
-+ *   is not supported
-+ */
-+
-+/**
-+ * struct virtio_jack - VirtIO jack.
-+ * @jack: Kernel jack control.
-+ * @nid: Functional group node identifier.
-+ * @features: Jack virtio feature bit map (1 << VIRTIO_SND_JACK_F_XXX).
-+ * @defconf: Pin default configuration value.
-+ * @caps: Pin capabilities value.
-+ * @connected: Current jack connection status.
-+ * @type: Kernel jack type (SND_JACK_XXX).
-+ */
-+struct virtio_jack {
-+      struct snd_jack *jack;
-+      u32 nid;
-+      u32 features;
-+      u32 defconf;
-+      u32 caps;
-+      bool connected;
-+      int type;
-+};
-+
-+/**
-+ * virtsnd_jack_get_label() - Get the name string for the jack.
-+ * @vjack: VirtIO jack.
-+ *
-+ * Returns the jack name based on the default pin configuration value (see HDA
-+ * specification).
-+ *
-+ * Context: Any context.
-+ * Return: Name string.
-+ */
-+static const char *virtsnd_jack_get_label(struct virtio_jack *vjack)
-+{
-+      unsigned int defconf = vjack->defconf;
-+      unsigned int device =
-+              (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
-+      unsigned int location =
-+              (defconf & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
-+
-+      switch (device) {
-+      case AC_JACK_LINE_OUT:
-+              return "Line Out";
-+      case AC_JACK_SPEAKER:
-+              return "Speaker";
-+      case AC_JACK_HP_OUT:
-+              return "Headphone";
-+      case AC_JACK_CD:
-+              return "CD";
-+      case AC_JACK_SPDIF_OUT:
-+      case AC_JACK_DIG_OTHER_OUT:
-+              if (location == AC_JACK_LOC_HDMI)
-+                      return "HDMI Out";
-+              else
-+                      return "SPDIF Out";
-+      case AC_JACK_LINE_IN:
-+              return "Line";
-+      case AC_JACK_AUX:
-+              return "Aux";
-+      case AC_JACK_MIC_IN:
-+              return "Mic";
-+      case AC_JACK_SPDIF_IN:
-+              return "SPDIF In";
-+      case AC_JACK_DIG_OTHER_IN:
-+              return "Digital In";
-+      default:
-+              return "Misc";
-+      }
-+}
-+
-+/**
-+ * virtsnd_jack_get_type() - Get the type for the jack.
-+ * @vjack: VirtIO jack.
-+ *
-+ * Returns the jack type based on the default pin configuration value (see HDA
-+ * specification).
-+ *
-+ * Context: Any context.
-+ * Return: SND_JACK_XXX value.
-+ */
-+static int virtsnd_jack_get_type(struct virtio_jack *vjack)
-+{
-+      unsigned int defconf = vjack->defconf;
-+      unsigned int device =
-+              (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
-+
-+      switch (device) {
-+      case AC_JACK_LINE_OUT:
-+      case AC_JACK_SPEAKER:
-+              return SND_JACK_LINEOUT;
-+      case AC_JACK_HP_OUT:
-+              return SND_JACK_HEADPHONE;
-+      case AC_JACK_SPDIF_OUT:
-+      case AC_JACK_DIG_OTHER_OUT:
-+              return SND_JACK_AVOUT;
-+      case AC_JACK_MIC_IN:
-+              return SND_JACK_MICROPHONE;
-+      default:
-+              return SND_JACK_LINEIN;
-+      }
-+}
-+
-+/**
-+ * virtsnd_jack_parse_cfg() - Parse the jack configuration.
-+ * @snd: VirtIO sound device.
-+ *
-+ * This function is called during initial device initialization.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_jack_parse_cfg(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_snd_jack_info *info;
-+      u32 i;
-+      int rc;
-+
-+      virtio_cread_le(vdev, struct virtio_snd_config, jacks, &snd->njacks);
-+      if (!snd->njacks)
-+              return 0;
-+
-+      snd->jacks = devm_kcalloc(&vdev->dev, snd->njacks, sizeof(*snd->jacks),
-+                                GFP_KERNEL);
-+      if (!snd->jacks)
-+              return -ENOMEM;
-+
-+      info = kcalloc(snd->njacks, sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return -ENOMEM;
-+
-+      rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_JACK_INFO, 0, snd->njacks,
-+                                  sizeof(*info), info);
-+      if (rc)
-+              goto on_exit;
-+
-+      for (i = 0; i < snd->njacks; ++i) {
-+              struct virtio_jack *vjack = &snd->jacks[i];
-+
-+              vjack->nid = le32_to_cpu(info[i].hdr.hda_fn_nid);
-+              vjack->features = le32_to_cpu(info[i].features);
-+              vjack->defconf = le32_to_cpu(info[i].hda_reg_defconf);
-+              vjack->caps = le32_to_cpu(info[i].hda_reg_caps);
-+              vjack->connected = info[i].connected;
-+      }
-+
-+on_exit:
-+      kfree(info);
-+
-+      return rc;
-+}
-+
-+/**
-+ * virtsnd_jack_build_devs() - Build ALSA controls for jacks.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_jack_build_devs(struct virtio_snd *snd)
-+{
-+      u32 i;
-+      int rc;
-+
-+      for (i = 0; i < snd->njacks; ++i) {
-+              struct virtio_jack *vjack = &snd->jacks[i];
-+
-+              vjack->type = virtsnd_jack_get_type(vjack);
-+
-+              rc = snd_jack_new(snd->card, virtsnd_jack_get_label(vjack),
-+                                vjack->type, &vjack->jack, true, true);
-+              if (rc)
-+                      return rc;
-+
-+              if (vjack->jack)
-+                      vjack->jack->private_data = vjack;
-+
-+              snd_jack_report(vjack->jack,
-+                              vjack->connected ? vjack->type : 0);
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_jack_event() - Handle the jack event notification.
-+ * @snd: VirtIO sound device.
-+ * @event: VirtIO sound event.
-+ *
-+ * Context: Interrupt context.
-+ */
-+void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event)
-+{
-+      u32 jack_id = le32_to_cpu(event->data);
-+      struct virtio_jack *vjack;
-+
-+      if (jack_id >= snd->njacks)
-+              return;
-+
-+      vjack = &snd->jacks[jack_id];
-+
-+      switch (le32_to_cpu(event->hdr.code)) {
-+      case VIRTIO_SND_EVT_JACK_CONNECTED:
-+              vjack->connected = true;
-+              break;
-+      case VIRTIO_SND_EVT_JACK_DISCONNECTED:
-+              vjack->connected = false;
-+              break;
-+      default:
-+              return;
-+      }
-+
-+      snd_jack_report(vjack->jack, vjack->connected ? vjack->type : 0);
-+}
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0008-ALSA-virtio-introduce-PCM-channel-map-support.patch
deleted file mode 100644 (file)
index d27ddb4..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-From 861932797d59b807b4fcc8a2e12dafbddd5ca4d9 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:08 +0100
-Subject: [PATCH] ALSA: virtio: introduce PCM channel map support
-
-Enumerate all available PCM channel maps and create ALSA controls.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-9-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/Makefile       |   1 +
- sound/virtio/virtio_card.c  |  10 ++
- sound/virtio/virtio_card.h  |   8 ++
- sound/virtio/virtio_chmap.c | 219 ++++++++++++++++++++++++++++++++++++
- sound/virtio/virtio_pcm.h   |   4 +
- 5 files changed, 242 insertions(+)
- create mode 100644 sound/virtio/virtio_chmap.c
-
-diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile
-index 09f485291285..2742bddb8874 100644
---- a/sound/virtio/Makefile
-+++ b/sound/virtio/Makefile
-@@ -4,6 +4,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
- virtio_snd-objs := \
-       virtio_card.o \
-+      virtio_chmap.o \
-       virtio_ctl_msg.o \
-       virtio_jack.o \
-       virtio_pcm.o \
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index 89bd66c1256e..1c03fcc41c3b 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -231,6 +231,10 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
-       if (rc)
-               return rc;
-+      rc = virtsnd_chmap_parse_cfg(snd);
-+      if (rc)
-+              return rc;
-+
-       if (snd->njacks) {
-               rc = virtsnd_jack_build_devs(snd);
-               if (rc)
-@@ -243,6 +247,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
-                       return rc;
-       }
-+      if (snd->nchmaps) {
-+              rc = virtsnd_chmap_build_devs(snd);
-+              if (rc)
-+                      return rc;
-+      }
-+
-       return snd_card_register(snd->card);
- }
-diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
-index f154313c79fd..86ef3941895e 100644
---- a/sound/virtio/virtio_card.h
-+++ b/sound/virtio/virtio_card.h
-@@ -43,6 +43,8 @@ struct virtio_snd_queue {
-  * @njacks: Number of jacks.
-  * @substreams: VirtIO PCM substreams.
-  * @nsubstreams: Number of PCM substreams.
-+ * @chmaps: VirtIO channel maps.
-+ * @nchmaps: Number of channel maps.
-  */
- struct virtio_snd {
-       struct virtio_device *vdev;
-@@ -55,6 +57,8 @@ struct virtio_snd {
-       u32 njacks;
-       struct virtio_pcm_substream *substreams;
-       u32 nsubstreams;
-+      struct virtio_snd_chmap_info *chmaps;
-+      u32 nchmaps;
- };
- /* Message completion timeout in milliseconds (module parameter). */
-@@ -100,4 +104,8 @@ int virtsnd_jack_build_devs(struct virtio_snd *snd);
- void virtsnd_jack_event(struct virtio_snd *snd,
-                       struct virtio_snd_event *event);
-+int virtsnd_chmap_parse_cfg(struct virtio_snd *snd);
-+
-+int virtsnd_chmap_build_devs(struct virtio_snd *snd);
-+
- #endif /* VIRTIO_SND_CARD_H */
-diff --git a/sound/virtio/virtio_chmap.c b/sound/virtio/virtio_chmap.c
-new file mode 100644
-index 000000000000..5bc924933a59
---- /dev/null
-+++ b/sound/virtio/virtio_chmap.c
-@@ -0,0 +1,219 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * virtio-snd: Virtio sound device
-+ * Copyright (C) 2021 OpenSynergy GmbH
-+ */
-+#include <linux/virtio_config.h>
-+
-+#include "virtio_card.h"
-+
-+/* VirtIO->ALSA channel position map */
-+static const u8 g_v2a_position_map[] = {
-+      [VIRTIO_SND_CHMAP_NONE] = SNDRV_CHMAP_UNKNOWN,
-+      [VIRTIO_SND_CHMAP_NA] = SNDRV_CHMAP_NA,
-+      [VIRTIO_SND_CHMAP_MONO] = SNDRV_CHMAP_MONO,
-+      [VIRTIO_SND_CHMAP_FL] = SNDRV_CHMAP_FL,
-+      [VIRTIO_SND_CHMAP_FR] = SNDRV_CHMAP_FR,
-+      [VIRTIO_SND_CHMAP_RL] = SNDRV_CHMAP_RL,
-+      [VIRTIO_SND_CHMAP_RR] = SNDRV_CHMAP_RR,
-+      [VIRTIO_SND_CHMAP_FC] = SNDRV_CHMAP_FC,
-+      [VIRTIO_SND_CHMAP_LFE] = SNDRV_CHMAP_LFE,
-+      [VIRTIO_SND_CHMAP_SL] = SNDRV_CHMAP_SL,
-+      [VIRTIO_SND_CHMAP_SR] = SNDRV_CHMAP_SR,
-+      [VIRTIO_SND_CHMAP_RC] = SNDRV_CHMAP_RC,
-+      [VIRTIO_SND_CHMAP_FLC] = SNDRV_CHMAP_FLC,
-+      [VIRTIO_SND_CHMAP_FRC] = SNDRV_CHMAP_FRC,
-+      [VIRTIO_SND_CHMAP_RLC] = SNDRV_CHMAP_RLC,
-+      [VIRTIO_SND_CHMAP_RRC] = SNDRV_CHMAP_RRC,
-+      [VIRTIO_SND_CHMAP_FLW] = SNDRV_CHMAP_FLW,
-+      [VIRTIO_SND_CHMAP_FRW] = SNDRV_CHMAP_FRW,
-+      [VIRTIO_SND_CHMAP_FLH] = SNDRV_CHMAP_FLH,
-+      [VIRTIO_SND_CHMAP_FCH] = SNDRV_CHMAP_FCH,
-+      [VIRTIO_SND_CHMAP_FRH] = SNDRV_CHMAP_FRH,
-+      [VIRTIO_SND_CHMAP_TC] = SNDRV_CHMAP_TC,
-+      [VIRTIO_SND_CHMAP_TFL] = SNDRV_CHMAP_TFL,
-+      [VIRTIO_SND_CHMAP_TFR] = SNDRV_CHMAP_TFR,
-+      [VIRTIO_SND_CHMAP_TFC] = SNDRV_CHMAP_TFC,
-+      [VIRTIO_SND_CHMAP_TRL] = SNDRV_CHMAP_TRL,
-+      [VIRTIO_SND_CHMAP_TRR] = SNDRV_CHMAP_TRR,
-+      [VIRTIO_SND_CHMAP_TRC] = SNDRV_CHMAP_TRC,
-+      [VIRTIO_SND_CHMAP_TFLC] = SNDRV_CHMAP_TFLC,
-+      [VIRTIO_SND_CHMAP_TFRC] = SNDRV_CHMAP_TFRC,
-+      [VIRTIO_SND_CHMAP_TSL] = SNDRV_CHMAP_TSL,
-+      [VIRTIO_SND_CHMAP_TSR] = SNDRV_CHMAP_TSR,
-+      [VIRTIO_SND_CHMAP_LLFE] = SNDRV_CHMAP_LLFE,
-+      [VIRTIO_SND_CHMAP_RLFE] = SNDRV_CHMAP_RLFE,
-+      [VIRTIO_SND_CHMAP_BC] = SNDRV_CHMAP_BC,
-+      [VIRTIO_SND_CHMAP_BLC] = SNDRV_CHMAP_BLC,
-+      [VIRTIO_SND_CHMAP_BRC] = SNDRV_CHMAP_BRC
-+};
-+
-+/**
-+ * virtsnd_chmap_parse_cfg() - Parse the channel map configuration.
-+ * @snd: VirtIO sound device.
-+ *
-+ * This function is called during initial device initialization.
-+ *
-+ * Context: Any context that permits to sleep.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_chmap_parse_cfg(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      u32 i;
-+      int rc;
-+
-+      virtio_cread_le(vdev, struct virtio_snd_config, chmaps, &snd->nchmaps);
-+      if (!snd->nchmaps)
-+              return 0;
-+
-+      snd->chmaps = devm_kcalloc(&vdev->dev, snd->nchmaps,
-+                                 sizeof(*snd->chmaps), GFP_KERNEL);
-+      if (!snd->chmaps)
-+              return -ENOMEM;
-+
-+      rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CHMAP_INFO, 0,
-+                                  snd->nchmaps, sizeof(*snd->chmaps),
-+                                  snd->chmaps);
-+      if (rc)
-+              return rc;
-+
-+      /* Count the number of channel maps per each PCM device/stream. */
-+      for (i = 0; i < snd->nchmaps; ++i) {
-+              struct virtio_snd_chmap_info *info = &snd->chmaps[i];
-+              u32 nid = le32_to_cpu(info->hdr.hda_fn_nid);
-+              struct virtio_pcm *vpcm;
-+              struct virtio_pcm_stream *vs;
-+
-+              vpcm = virtsnd_pcm_find_or_create(snd, nid);
-+              if (IS_ERR(vpcm))
-+                      return PTR_ERR(vpcm);
-+
-+              switch (info->direction) {
-+              case VIRTIO_SND_D_OUTPUT:
-+                      vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK];
-+                      break;
-+              case VIRTIO_SND_D_INPUT:
-+                      vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE];
-+                      break;
-+              default:
-+                      dev_err(&vdev->dev,
-+                              "chmap #%u: unknown direction (%u)\n", i,
-+                              info->direction);
-+                      return -EINVAL;
-+              }
-+
-+              vs->nchmaps++;
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_chmap_add_ctls() - Create an ALSA control for channel maps.
-+ * @pcm: ALSA PCM device.
-+ * @direction: PCM stream direction (SNDRV_PCM_STREAM_XXX).
-+ * @vs: VirtIO PCM stream.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_chmap_add_ctls(struct snd_pcm *pcm, int direction,
-+                                struct virtio_pcm_stream *vs)
-+{
-+      u32 i;
-+      int max_channels = 0;
-+
-+      for (i = 0; i < vs->nchmaps; i++)
-+              if (max_channels < vs->chmaps[i].channels)
-+                      max_channels = vs->chmaps[i].channels;
-+
-+      return snd_pcm_add_chmap_ctls(pcm, direction, vs->chmaps, max_channels,
-+                                    0, NULL);
-+}
-+
-+/**
-+ * virtsnd_chmap_build_devs() - Build ALSA controls for channel maps.
-+ * @snd: VirtIO sound device.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+int virtsnd_chmap_build_devs(struct virtio_snd *snd)
-+{
-+      struct virtio_device *vdev = snd->vdev;
-+      struct virtio_pcm *vpcm;
-+      struct virtio_pcm_stream *vs;
-+      u32 i;
-+      int rc;
-+
-+      /* Allocate channel map elements per each PCM device/stream. */
-+      list_for_each_entry(vpcm, &snd->pcm_list, list) {
-+              for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) {
-+                      vs = &vpcm->streams[i];
-+
-+                      if (!vs->nchmaps)
-+                              continue;
-+
-+                      vs->chmaps = devm_kcalloc(&vdev->dev, vs->nchmaps + 1,
-+                                                sizeof(*vs->chmaps),
-+                                                GFP_KERNEL);
-+                      if (!vs->chmaps)
-+                              return -ENOMEM;
-+
-+                      vs->nchmaps = 0;
-+              }
-+      }
-+
-+      /* Initialize channel maps per each PCM device/stream. */
-+      for (i = 0; i < snd->nchmaps; ++i) {
-+              struct virtio_snd_chmap_info *info = &snd->chmaps[i];
-+              unsigned int channels = info->channels;
-+              unsigned int ch;
-+              struct snd_pcm_chmap_elem *chmap;
-+
-+              vpcm = virtsnd_pcm_find(snd, le32_to_cpu(info->hdr.hda_fn_nid));
-+              if (IS_ERR(vpcm))
-+                      return PTR_ERR(vpcm);
-+
-+              if (info->direction == VIRTIO_SND_D_OUTPUT)
-+                      vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK];
-+              else
-+                      vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE];
-+
-+              chmap = &vs->chmaps[vs->nchmaps++];
-+
-+              if (channels > ARRAY_SIZE(chmap->map))
-+                      channels = ARRAY_SIZE(chmap->map);
-+
-+              chmap->channels = channels;
-+
-+              for (ch = 0; ch < channels; ++ch) {
-+                      u8 position = info->positions[ch];
-+
-+                      if (position >= ARRAY_SIZE(g_v2a_position_map))
-+                              return -EINVAL;
-+
-+                      chmap->map[ch] = g_v2a_position_map[position];
-+              }
-+      }
-+
-+      /* Create an ALSA control per each PCM device/stream. */
-+      list_for_each_entry(vpcm, &snd->pcm_list, list) {
-+              if (!vpcm->pcm)
-+                      continue;
-+
-+              for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) {
-+                      vs = &vpcm->streams[i];
-+
-+                      if (!vs->nchmaps)
-+                              continue;
-+
-+                      rc = virtsnd_chmap_add_ctls(vpcm->pcm, i, vs);
-+                      if (rc)
-+                              return rc;
-+              }
-+      }
-+
-+      return 0;
-+}
-diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
-index efd0228746cf..1353fdc9bd69 100644
---- a/sound/virtio/virtio_pcm.h
-+++ b/sound/virtio/virtio_pcm.h
-@@ -63,10 +63,14 @@ struct virtio_pcm_substream {
-  * struct virtio_pcm_stream - VirtIO PCM stream.
-  * @substreams: VirtIO substreams belonging to the stream.
-  * @nsubstreams: Number of substreams.
-+ * @chmaps: Kernel channel maps belonging to the stream.
-+ * @nchmaps: Number of channel maps.
-  */
- struct virtio_pcm_stream {
-       struct virtio_pcm_substream **substreams;
-       u32 nsubstreams;
-+      struct snd_pcm_chmap_elem *chmaps;
-+      u32 nchmaps;
- };
- /**
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0009-ALSA-virtio-introduce-device-suspend-resume-support.patch b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto/virtio-kmeta/bsp/virtio/virtio-snd/0009-ALSA-virtio-introduce-device-suspend-resume-support.patch
deleted file mode 100644 (file)
index b7d278f..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-From b173fb2a0eb0067fc665ba48f9b2b8b5f991c078 Mon Sep 17 00:00:00 2001
-From: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Date: Tue, 2 Mar 2021 17:47:09 +0100
-Subject: [PATCH] ALSA: virtio: introduce device suspend/resume support
-
-All running PCM substreams are stopped on device suspend and restarted
-on device resume.
-
-Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
-Link: https://lore.kernel.org/r/20210302164709.3142702-10-anton.yakovlev@opensynergy.com
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
----
- sound/virtio/virtio_card.c    | 56 +++++++++++++++++++++++++++++++++++
- sound/virtio/virtio_pcm.h     |  3 ++
- sound/virtio/virtio_pcm_ops.c | 33 ++++++++++++++++-----
- 3 files changed, 85 insertions(+), 7 deletions(-)
-
-diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
-index 1c03fcc41c3b..ae9128063917 100644
---- a/sound/virtio/virtio_card.c
-+++ b/sound/virtio/virtio_card.c
-@@ -362,6 +362,58 @@ static void virtsnd_remove(struct virtio_device *vdev)
-       kfree(snd->event_msgs);
- }
-+#ifdef CONFIG_PM_SLEEP
-+/**
-+ * virtsnd_freeze() - Suspend device.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_freeze(struct virtio_device *vdev)
-+{
-+      struct virtio_snd *snd = vdev->priv;
-+      unsigned int i;
-+
-+      virtsnd_disable_event_vq(snd);
-+      virtsnd_ctl_msg_cancel_all(snd);
-+
-+      vdev->config->del_vqs(vdev);
-+      vdev->config->reset(vdev);
-+
-+      for (i = 0; i < snd->nsubstreams; ++i)
-+              cancel_work_sync(&snd->substreams[i].elapsed_period);
-+
-+      kfree(snd->event_msgs);
-+      snd->event_msgs = NULL;
-+
-+      return 0;
-+}
-+
-+/**
-+ * virtsnd_restore() - Resume device.
-+ * @vdev: VirtIO parent device.
-+ *
-+ * Context: Any context.
-+ * Return: 0 on success, -errno on failure.
-+ */
-+static int virtsnd_restore(struct virtio_device *vdev)
-+{
-+      struct virtio_snd *snd = vdev->priv;
-+      int rc;
-+
-+      rc = virtsnd_find_vqs(snd);
-+      if (rc)
-+              return rc;
-+
-+      virtio_device_ready(vdev);
-+
-+      virtsnd_enable_event_vq(snd);
-+
-+      return 0;
-+}
-+#endif /* CONFIG_PM_SLEEP */
-+
- static const struct virtio_device_id id_table[] = {
-       { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
-       { 0 },
-@@ -374,6 +426,10 @@ static struct virtio_driver virtsnd_driver = {
-       .validate = virtsnd_validate,
-       .probe = virtsnd_probe,
-       .remove = virtsnd_remove,
-+#ifdef CONFIG_PM_SLEEP
-+      .freeze = virtsnd_freeze,
-+      .restore = virtsnd_restore,
-+#endif
- };
- static int __init init(void)
-diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
-index 1353fdc9bd69..062eb8e8f2cf 100644
---- a/sound/virtio/virtio_pcm.h
-+++ b/sound/virtio/virtio_pcm.h
-@@ -31,6 +31,8 @@ struct virtio_pcm_msg;
-  * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
-  * @stopped: True if the substream is stopped and must be released on the device
-  *           side.
-+ * @suspended: True if the substream is suspended and must be reconfigured on
-+ *             the device side at resume.
-  * @msgs: Allocated I/O messages.
-  * @nmsgs: Number of allocated I/O messages.
-  * @msg_last_enqueued: Index of the last I/O message added to the virtqueue.
-@@ -52,6 +54,7 @@ struct virtio_pcm_substream {
-       bool xfer_enabled;
-       bool xfer_xrun;
-       bool stopped;
-+      bool suspended;
-       struct virtio_pcm_msg **msgs;
-       unsigned int nmsgs;
-       int msg_last_enqueued;
-diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
-index 0682a2df6c8c..f8bfb87624be 100644
---- a/sound/virtio/virtio_pcm_ops.c
-+++ b/sound/virtio/virtio_pcm_ops.c
-@@ -115,6 +115,7 @@ static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
-                                     SNDRV_PCM_HW_PARAM_PERIODS);
-       vss->stopped = !!virtsnd_pcm_msg_pending_num(vss);
-+      vss->suspended = false;
-       /*
-        * If the substream has already been used, then the I/O queue may be in
-@@ -272,16 +273,31 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
-       struct virtio_device *vdev = vss->snd->vdev;
-       struct virtio_snd_msg *msg;
--      if (virtsnd_pcm_msg_pending_num(vss)) {
--              dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
--                      vss->sid);
--              return -EBADFD;
-+      if (!vss->suspended) {
-+              if (virtsnd_pcm_msg_pending_num(vss)) {
-+                      dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
-+                              vss->sid);
-+                      return -EBADFD;
-+              }
-+
-+              vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-+              vss->hw_ptr = 0;
-+              vss->msg_last_enqueued = -1;
-+      } else {
-+              struct snd_pcm_runtime *runtime = substream->runtime;
-+              unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-+              unsigned int period_bytes = snd_pcm_lib_period_bytes(substream);
-+              int rc;
-+
-+              rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes,
-+                                              runtime->channels,
-+                                              runtime->format, runtime->rate);
-+              if (rc)
-+                      return rc;
-       }
--      vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
--      vss->hw_ptr = 0;
-       vss->xfer_xrun = false;
--      vss->msg_last_enqueued = -1;
-+      vss->suspended = false;
-       vss->msg_count = 0;
-       msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE,
-@@ -336,6 +352,9 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command)
-               }
-               return virtsnd_ctl_msg_send_sync(snd, msg);
-+      case SNDRV_PCM_TRIGGER_SUSPEND:
-+              vss->suspended = true;
-+              fallthrough;
-       case SNDRV_PCM_TRIGGER_STOP:
-               vss->stopped = true;
-               fallthrough;
index ba7b4ce..a1fc8bb 100644 (file)
@@ -1,11 +1,2 @@
 # SPDX-License-Identifier: MIT
 kconf hardware virtio-snd.cfg
-patch 0001-uapi-virtio_ids-add-a-sound-device-type-ID-from-OASI.patch
-patch 0002-ALSA-virtio-add-virtio-sound-driver.patch
-patch 0003-ALSA-virtio-handling-control-messages.patch
-patch 0004-ALSA-virtio-build-PCM-devices-and-substream-hardware.patch
-patch 0005-ALSA-virtio-handling-control-and-I-O-messages-for-th.patch
-patch 0006-ALSA-virtio-PCM-substream-operators.patch
-patch 0007-ALSA-virtio-introduce-jack-support.patch
-patch 0008-ALSA-virtio-introduce-PCM-channel-map-support.patch
-patch 0009-ALSA-virtio-introduce-device-suspend-resume-support.patch
index 0f255cd..8b5e92a 100644 (file)
@@ -5,4 +5,4 @@ SRC_URI:append:virtio-all = " \
     file://virtio-kmeta/bsp/virtio/virtio-aarch64-${LINUX_KERNEL_TYPE}.scc \
 "
 
-COMPATIBLE_MACHINE_virtio-aarch64 = "virtio-aarch64"
+COMPATIBLE_MACHINE:virtio-aarch64 = "virtio-aarch64"
diff --git a/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto_5.10.bb b/meta-agl-bsp/virtualization-layer/recipes-kernel/linux/linux-yocto_5.10.bb
deleted file mode 100644 (file)
index 322ae51..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-KBRANCH ?= "v5.10/standard/base"
-
-require recipes-kernel/linux/linux-yocto.inc
-
-# board specific branches
-KBRANCH:qemuarm  ?= "v5.10/standard/arm-versatile-926ejs"
-KBRANCH:qemuarm64 ?= "v5.10/standard/qemuarm64"
-KBRANCH:qemumips ?= "v5.10/standard/mti-malta32"
-KBRANCH:qemuppc  ?= "v5.10/standard/qemuppc"
-KBRANCH:qemuriscv64  ?= "v5.10/standard/base"
-KBRANCH:qemuriscv32  ?= "v5.10/standard/base"
-KBRANCH:qemux86  ?= "v5.10/standard/base"
-KBRANCH:qemux86-64 ?= "v5.10/standard/base"
-KBRANCH:qemumips64 ?= "v5.10/standard/mti-malta64"
-
-SRCREV_machine:qemuarm ?= "d8551cae1ccdbe062a5c6068ce39ea8f4e1c72db"
-SRCREV_machine:qemuarm64 ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemumips ?= "7f1f1ad2f2d90b1b070c6b0a82f0add9aa492e37"
-SRCREV_machine:qemuppc ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemuriscv64 ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemuriscv32 ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemux86 ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemux86-64 ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_machine:qemumips64 ?= "fd5ac097b891642eea13659bea536f3ec5910d6d"
-SRCREV_machine ?= "cf5b0320cf4544d3db9ce3ddd6ddb7553a610651"
-SRCREV_meta ?= "031f6c76e488a3563f35258c72ff1de3e25a512e"
-
-# remap qemuarm to qemuarma15 for the 5.8 kernel
-# KMACHINE:qemuarm ?= "qemuarma15"
-
-SRC_URI = "git://git.yoctoproject.org/linux-yocto.git;name=machine;branch=${KBRANCH}; \
-           git://git.yoctoproject.org/yocto-kernel-cache;type=kmeta;name=meta;branch=yocto-5.10;destsuffix=${KMETA}"
-
-LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"
-LINUX_VERSION ?= "5.10.25"
-
-DEPENDS += "${@bb.utils.contains('ARCH', 'x86', 'elfutils-native', '', d)}"
-DEPENDS += "openssl-native util-linux-native"
-DEPENDS += "gmp-native"
-
-PV = "${LINUX_VERSION}+git${SRCPV}"
-
-KMETA = "kernel-meta"
-KCONF_BSP_AUDIT_LEVEL = "1"
-
-KERNEL_DEVICETREE:qemuarmv5 = "versatile-pb.dtb"
-
-COMPATIBLE_MACHINE = "qemuarm|qemuarmv5|qemuarm64|qemux86|qemuppc|qemuppc64|qemumips|qemumips64|qemux86-64|qemuriscv64|qemuriscv32"
-
-# Functionality flags
-KERNEL_EXTRA_FEATURES ?= "features/netfilter/netfilter.scc"
-KERNEL_FEATURES:append = " ${KERNEL_EXTRA_FEATURES}"
-KERNEL_FEATURES:append:qemuall=" cfg/virtio.scc features/drm-bochs/drm-bochs.scc"
-KERNEL_FEATURES:append:qemux86=" cfg/sound.scc cfg/paravirt_kvm.scc"
-KERNEL_FEATURES:append:qemux86-64=" cfg/sound.scc cfg/paravirt_kvm.scc"
-KERNEL_FEATURES:append = " ${@bb.utils.contains("TUNE_FEATURES", "mx32", " cfg/x32.scc", "", d)}"
-KERNEL_FEATURES:append = " ${@bb.utils.contains("DISTRO_FEATURES", "ptest", " features/scsi/scsi-debug.scc", "", d)}"
-KERNEL_FEATURES:append = " ${@bb.utils.contains("DISTRO_FEATURES", "ptest", " features/gpio/mockup.scc", "", d)}"
\ No newline at end of file