Re: [v2 PATCH 0/1] ALSA: virtio: add support for audio controls

2024-02-19 Thread Anton Yakovlev

Hi Marcin,


Thanks for the help!



On 20.02.2024 02:24, Marcin Radomski wrote:

Thanks Anton for the reupload.

I tested this series with a 6.1 kernel guest on a proprietary hypervisor. The
controls exposed by the host (BOOLEAN/INTEGER ones, as that was all I could
get) worked as expected when adjusted via ALSA APIs.

Reviewed-by: Marcin Radomski 
Tested-By: Marcin Radomski 


--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v2] uml: fix W=1 missing-include-dirs warnings

2021-04-16 Thread Anton Ivanov

On 15/04/2021 18:13, Randy Dunlap wrote:

Currently when using "W=1" with UML builds, there are over 700 warnings
like so:

   CC  arch/um/drivers/stderr_console.o
cc1: warning: ./arch/um/include/uapi: No such file or directory 
[-Wmissing-include-dirs]

but arch/um/ does not have include/uapi/ at all, so add that
subdir and put one Kbuild file into it (since git does not track
empty subdirs).

Signed-off-by: Randy Dunlap 
Cc: Masahiro Yamada 
Cc: Michal Marek 
Cc: linux-kbu...@vger.kernel.org
Cc: Jeff Dike 
Cc: Richard Weinberger 
Cc: Anton Ivanov 
Cc: linux...@lists.infradead.org
---
v2: use Option 4 from v1: add arch/um/include/uapi so that 'make' is
 placated -- and just like all other arch's have.

  arch/um/include/uapi/asm/Kbuild |1 +
  1 file changed, 1 insertion(+)

diff --git a/arch/um/include/uapi/asm/Kbuild b/arch/um/include/uapi/asm/Kbuild
new file mode 100644
index ..f66554cd5c45
--- /dev/null
+++ b/arch/um/include/uapi/asm/Kbuild
@@ -0,0 +1 @@
+# SPDX-License-Identifier: GPL-2.0

___
linux-um mailing list
linux...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


+1

I will forward it to openwrt-dev. Their build process adds uapi to uml, 
so if we are going to change this, it will be nice to give them a heads-up.


Acked-By: Anton Ivanov 


--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/



Re: [PATCH] sound: virtio: correct the function name in kernel-doc comment

2021-04-15 Thread Anton Yakovlev

On 15.04.2021 07:26, Randy Dunlap wrote:


Fix kernel-doc warning that the wrong function name is used in a
kernel-doc comment:

../sound/virtio/virtio_ctl_msg.c:70: warning: expecting prototype for 
virtsnd_ctl_msg_request(). Prototype was for virtsnd_ctl_msg_response() instead

Signed-off-by: Randy Dunlap 
Cc: Anton Yakovlev 
Cc: "Michael S. Tsirkin" 
Cc: virtualizat...@lists.linux-foundation.org
Cc: alsa-de...@alsa-project.org


Thanks for fixing the copy/paste mistake. :)

Reviewed-by: Anton Yakovlev 


---
  sound/virtio/virtio_ctl_msg.c |2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

--- linux-next-20210414.orig/sound/virtio/virtio_ctl_msg.c
+++ linux-next-20210414/sound/virtio/virtio_ctl_msg.c
@@ -61,7 +61,7 @@ void *virtsnd_ctl_msg_request(struct vir
  }

  /**
- * virtsnd_ctl_msg_request() - Get a pointer to the response header.
+ * virtsnd_ctl_msg_response() - Get a pointer to the response header.
   * @msg: Control message.
   *
   * Context: Any context.



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH 0/4 POC] Allow executing code and syscalls in another address space

2021-04-14 Thread Anton Ivanov

On 14/04/2021 06:52, Andrei Vagin wrote:

We already have process_vm_readv and process_vm_writev to read and write
to a process memory faster than we can do this with ptrace. And now it
is time for process_vm_exec that allows executing code in an address
space of another process. We can do this with ptrace but it is much
slower.

= Use-cases =

Here are two known use-cases. The first one is “application kernel”
sandboxes like User-mode Linux and gVisor. In this case, we have a
process that runs the sandbox kernel and a set of stub processes that
are used to manage guest address spaces. Guest code is executed in the
context of stub processes but all system calls are intercepted and
handled in the sandbox kernel. Right now, these sort of sandboxes use
PTRACE_SYSEMU to trap system calls, but the process_vm_exec can
significantly speed them up.


Certainly interesting, but will require um to rework most of its memory 
management and we will most likely need extra mm support to make use of 
it in UML. We are not likely to get away just with one syscall there.




Another use-case is CRIU (Checkpoint/Restore in User-space). Several
process properties can be received only from the process itself. Right
now, we use a parasite code that is injected into the process. We do
this with ptrace but it is slow, unsafe, and tricky. process_vm_exec can
simplify the process of injecting a parasite code and it will allow
pre-dump memory without stopping processes. The pre-dump here is when we
enable a memory tracker and dump the memory while a process is continue
running. On each interaction we dump memory that has been changed from
the previous iteration. In the final step, we will stop processes and
dump their full state. Right now the most effective way to dump process
memory is to create a set of pipes and splice memory into these pipes
from the parasite code. With process_vm_exec, we will be able to call
vmsplice directly. It means that we will not need to stop a process to
inject the parasite code.

= How it works =

process_vm_exec has two modes:

* Execute code in an address space of a target process and stop on any
   signal or system call.

* Execute a system call in an address space of a target process.

int process_vm_exec(pid_t pid, struct sigcontext uctx,
unsigned long flags, siginfo_t siginfo,
sigset_t  *sigmask, size_t sizemask)

PID - target process identification. We can consider to use pidfd
instead of PID here.

sigcontext contains a process state with what the process will be
resumed after switching the address space and then when a process will
be stopped, its sate will be saved back to sigcontext.

siginfo is information about a signal that has interrupted the process.
If a process is interrupted by a system call, signfo will contain a
synthetic siginfo of the SIGSYS signal.

sigmask is a set of signals that process_vm_exec returns via signfo.

# How fast is it

In the fourth patch, you can find two benchmarks that execute a function
that calls system calls in a loop. ptrace_vm_exe uses ptrace to trap
system calls, proces_vm_exec uses the process_vm_exec syscall to do the
same thing.

ptrace_vm_exec:   1446 ns/syscall
ptrocess_vm_exec:  289 ns/syscall

PS: This version is just a prototype. Its goal is to collect the initial
feedback, to discuss the interfaces, and maybe to get some advice on
implementation..

Cc: Andrew Morton 
Cc: Andy Lutomirski 
Cc: Anton Ivanov 
Cc: Christian Brauner 
Cc: Dmitry Safonov <0x7f454...@gmail.com>
Cc: Ingo Molnar 
Cc: Jeff Dike 
Cc: Mike Rapoport 
Cc: Michael Kerrisk (man-pages) 
Cc: Oleg Nesterov 
Cc: Peter Zijlstra 
Cc: Richard Weinberger 
Cc: Thomas Gleixner 

Andrei Vagin (4):
   signal: add a helper to restore a process state from sigcontex
   arch/x86: implement the process_vm_exec syscall
   arch/x86: allow to execute syscalls via process_vm_exec
   selftests: add tests for process_vm_exec

  arch/Kconfig  |  15 ++
  arch/x86/Kconfig  |   1 +
  arch/x86/entry/common.c   |  19 +++
  arch/x86/entry/syscalls/syscall_64.tbl|   1 +
  arch/x86/include/asm/sigcontext.h |   2 +
  arch/x86/kernel/Makefile  |   1 +
  arch/x86/kernel/process_vm_exec.c | 160 ++
  arch/x86/kernel/signal.c  | 125 ++
  include/linux/entry-common.h  |   2 +
  include/linux/process_vm_exec.h   |  17 ++
  include/linux/sched.h |   7 +
  include/linux/syscalls.h  |   6 +
  include/uapi/asm-generic/unistd.h |   4 +-
  include/uapi/linux/process_vm_exec.h  |   8 +
  kernel/entry/common.c |   2 +-
  kernel/fork.c |   9 +
  kernel/sys_ni.c   |   2 +
  .../selftests/process_vm_exec/Makefile|   7 +
 

Re: [PATCH -next] ALSA: virtio: use module_virtio_driver() to simplify the code

2021-04-10 Thread Anton Yakovlev

On 08.04.2021 14:54, Chen Huang wrote


module_virtio_driver() makes the code simpler by eliminating
boilerplate code.

Signed-off-by: Chen Huang 


Thanks for the patch.

Reviewed-by: Anton Yakovlev 


---
  sound/virtio/virtio_card.c | 12 +---
  1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index ae9128063917..150ab3e37013 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -432,17 +432,7 @@ static struct virtio_driver virtsnd_driver = {
  #endif
  };

-static int __init init(void)
-{
-   return register_virtio_driver(_driver);
-}
-module_init(init);
-
-static void __exit fini(void)
-{
-   unregister_virtio_driver(_driver);
-}
-module_exit(fini);
+module_virtio_driver(virtsnd_driver);

  MODULE_DEVICE_TABLE(virtio, id_table);
  MODULE_DESCRIPTION("Virtio sound card driver");
--
2.17.1






Re: [PATCH] um: add 2 missing libs to fix various build errors

2021-04-09 Thread Anton Ivanov

On 10/04/2021 05:13, Randy Dunlap wrote:

On 4/4/21 11:20 AM, Randy Dunlap wrote:

Fix many build errors (at least 18 build error reports) for uml on i386
by adding 2 more library object files. All missing symbols are
either cmpxchg8b_emu or atomic*386.

Here are a few examples of the build errors that are eliminated:

/usr/bin/ld: core.c:(.text+0xd83): undefined reference to `cmpxchg8b_emu'
/usr/bin/ld: core.c:(.text+0x2bb2): undefined reference to 
`atomic64_add_386'
/usr/bin/ld: core.c:(.text+0x2c5d): undefined reference to 
`atomic64_xchg_386'
syscall.c:(.text+0x2f49): undefined reference to `atomic64_set_386'
/usr/bin/ld: syscall.c:(.text+0x2f54): undefined reference to 
`atomic64_set_386'
syscall.c:(.text+0x33a4): undefined reference to `atomic64_inc_386'
/usr/bin/ld: syscall.c:(.text+0x33ac): undefined reference to 
`atomic64_inc_386'
/usr/bin/ld: net/ipv4/inet_timewait_sock.o: in function `inet_twsk_alloc':
inet_timewait_sock.c:(.text+0x3d1): undefined reference to 
`atomic64_read_386'
/usr/bin/ld: inet_timewait_sock.c:(.text+0x3dd): undefined reference to 
`atomic64_set_386'
/usr/bin/ld: net/ipv4/inet_connection_sock.o: in function 
`inet_csk_clone_lock':
inet_connection_sock.c:(.text+0x1d74): undefined reference to 
`atomic64_read_386'
/usr/bin/ld: inet_connection_sock.c:(.text+0x1d80): undefined reference to 
`atomic64_set_386'
/usr/bin/ld: net/ipv4/tcp_input.o: in function `inet_reqsk_alloc':
tcp_input.c:(.text+0xa345): undefined reference to `atomic64_set_386'
/usr/bin/ld: net/mac80211/wpa.o: in function 
`ieee80211_crypto_tkip_encrypt':
wpa.c:(.text+0x739): undefined reference to `atomic64_inc_return_386'

Signed-off-by: Randy Dunlap 
Reported-by: kernel test robot 
Cc: Brendan Jackman 
Cc: Alexei Starovoitov 
Cc: kbuild-...@lists.01.org
Cc: Jeff Dike 
Cc: Richard Weinberger 
Cc: Anton Ivanov 
Cc: linux...@lists.infradead.org
Cc: Johannes Berg 
Cc: Johannes Berg 
---
My UML on i386 build environment is br0ken so this is not tested other
than to see that the .o files are built as expected.
If someone can test/verify it, please respond. Thanks.


Hi,
Instead of trying to build this on x86_64, I powered up my 32-bit x86
laptop and verified that this patch fixes the build errors of
undefined references to cmpxchg8b_emu() and atomic64_*_386() functions.

There are still some build errors in 2 object files:

/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x8): undefined reference to 
`X86_FEATURE_XMM2'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x15): undefined reference to 
`X86_FEATURE_XMM2'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x22): undefined reference to 
`X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x2f): undefined reference to 
`X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x3c): undefined reference to 
`X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x49): undefined reference to 
`X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x56): undefined reference to 
`X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
kernel/irq/generic-chip.o:(.altinstructions+0x63): more undefined references to 
`X86_FEATURE_XMM' follow

and

/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x8): undefined reference to 
`X86_FEATURE_XMM2'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x15): undefined reference 
to `X86_FEATURE_XMM2'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x22): undefined reference 
to `X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x2f): undefined reference 
to `X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x3c): undefined reference 
to `X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x49): undefined reference 
to `X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld: 
drivers/fpga/altera-pr-ip-core.o:(.altinstructions+0x56): undefined reference 
to `X86_FEATURE_XMM'
/usr/lib/gcc/i586-suse-linux/10/../../../../i586-suse-linux/bin/ld

Re: [PATCH v2] ARM: dts: nuvoton: Fix flash layout

2021-03-24 Thread Anton Kachalov
Gently ping

On Mon, 8 Mar 2021 at 18:11,  wrote:
>
> From: "Anton D. Kachalov" 
>
> This change follows OpenBMC partitions' naming layout.
>
> Signed-off-by: Anton D. Kachalov 
> ---
>  arch/arm/boot/dts/nuvoton-npcm750-evb.dts | 38 +++
>  1 file changed, 11 insertions(+), 27 deletions(-)
>
> diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts 
> b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> index 9f13d08f5804..55c5a89592d7 100644
> --- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> +++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> @@ -78,8 +78,8 @@ partitions@8000 {
> compatible = "fixed-partitions";
> #address-cells = <1>;
> #size-cells = <1>;
> -   bbuboot1@0 {
> -   label = "bb-uboot-1";
> +   u-boot@0 {
> +   label = "u-boot";
> reg = <0x000 0x8>;
> read-only;
> };
> @@ -88,38 +88,22 @@ bbuboot2@8 {
> reg = <0x008 0x8>;
> read-only;
> };
> -   envparam@10 {
> -   label = "env-param";
> +   u-boot-env@10 {
> +   label = "u-boot-env";
> reg = <0x010 0x4>;
> read-only;
> };
> -   spare@14 {
> -   label = "spare";
> -   reg = <0x014 0xC>;
> -   };
> kernel@20 {
> label = "kernel";
> -   reg = <0x020 0x40>;
> -   };
> -   rootfs@60 {
> -   label = "rootfs";
> -   reg = <0x060 0x70>;
> -   };
> -   spare1@D0 {
> -   label = "spare1";
> -   reg = <0x0D0 0x20>;
> -   };
> -   spare2@0F0 {
> -   label = "spare2";
> -   reg = <0x0F0 0x20>;
> +   reg = <0x020 0x58>;
> };
> -   spare3@110 {
> -   label = "spare3";
> -   reg = <0x110 0x20>;
> +   rofs@78 {
> +   label = "rofs";
> +   reg = <0x078 0x168>;
> };
> -   spare4@130 {
> -   label = "spare4";
> -   reg = <0x130 0x0>;
> +   rwfs@1e0 {
> +   label = "rwfs";
> +   reg = <0x1e0 0x20>;
> };
> };
> };
> --
> 2.30.1.766.gb4fecdf3b7-goog
>


[PATCH v7 6/9] ALSA: virtio: PCM substream operators

2021-03-02 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 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, _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 ..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 
+
+#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, VIRT

[PATCH v7 7/9] ALSA: virtio: introduce jack support

2021-03-02 Thread Anton Yakovlev
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 
---
 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 ..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 
+#include 
+#include 
+
+#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

[PATCH v7 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-03-02 Thread Anton Yakovlev
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 
---
 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(>ctl_msgs);
+   INIT_LIST_HEAD(>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(>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 
 
 #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 ..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 
+#include 
+
+#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 pe

[PATCH v7 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-03-02 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.1




[PATCH v7 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-03-02 Thread Anton Yakovlev
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 
---
 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(>substreams[i].elapsed_period);
+   for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
+   struct virtio_pcm_substream *vss = >substreams[i];
+
+   cancel_work_sync(>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 >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(>elapsed_period, virtsnd_pcm_period_elapsed);
+   init_waitqueue_head(>msg_empty);
+   spin_lock_init(>lock);
 
rc = virtsnd_pcm_build_hw(vss, [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(s

[PATCH v7 8/9] ALSA: virtio: introduce PCM channel map support

2021-03-02 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 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 ..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 
+
+#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() -

[PATCH v7 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-02 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 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(>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(>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(>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,
+   

[PATCH v7 2/9] ALSA: virtio: add virtio sound driver

2021-03-02 Thread Anton Yakovlev
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 
---
 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 c71664ca8bfd..4369946434ad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19049,6 +19049,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..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 
+
+/***
+ * 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 

[PATCH v7 3/9] ALSA: virtio: handling control messages

2021-03-02 Thread Anton Yakovlev
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 
---
 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(>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(>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 
 #include 
 
+#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 ..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 
+#include 
+
+#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.

Re: [PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-02 Thread Anton Yakovlev

On 02.03.2021 10:11, Takashi Iwai wrote:

On Tue, 02 Mar 2021 09:09:33 +0100,
Anton Yakovlev wrote:


On 02.03.2021 07:48, Takashi Iwai wrote:

On Tue, 02 Mar 2021 07:29:20 +0100,
Anton Yakovlev wrote:


On 28.02.2021 13:05, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:56 +0100,
Anton Yakovlev wrote:




[snip]


--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
 SNDRV_PCM_INFO_BATCH |
 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME |
 SNDRV_PCM_INFO_PAUSE;


Actually you don't need to set SNDRV_PCM_INFO_RESUME.
This flag means that the driver supports the full resume procedure,
which isn't often the case; with this, the driver is supposed to
resume the stream exactly from the suspended position.

Most drivers don't set this but implement only the suspend-stop
action.  Then the application (or the sound backend) will re-setup the
stream and restart accordingly.


I tried to resume driver without SNDRV_PCM_INFO_RESUME, and alsa-lib
called only ops->prepare(). It makes sense for a typical hw, but we have
"clean" unconfigured device on resume. And we must set hw parameters as
a first step. It means, that code should be more or less the same. And
maybe it's better to set SNDRV_PCM_INFO_RESUME, since it allows us to
resume substream in any situation (regardless of application behavior).
I can refactor code to only send requests from trigger(RESUME) path and
not to call ops itself. It should make code more straitforward. What do
you say?


How about calling hw_params(NULL) conditionally in the prepare?


Then the question is that condition. When ops->prepare() is called, the
substream is in SUSPENDED state or not? If not then we need to track
this in some additional field (and it will make logic a little bit
clumsy, since that field is needed to be carefully handled in other
places).


Yes, you'd need to have a suspend/resume PM callback in the driver
that flips the internal flag to invalidate the hw_parmas, and in the
prepare callback, just call hw_params(NULL) if that flag is set.


Doing the full stack work in the trigger callback is bad from the API
design POV; in general the trigger callback is supposed to be as short
as possible.


Yeah, but usually original subsystem design does not take into account
para-virtualized devices, which usually have it's own slightly different
reality. And we need to introduce some tricks.


The hardware drivers do a lot of more things in either suspend/resume
PM callbacks or prepare callback for re-setup of the hardware.  We can
follow the similar pattern.  Heavy-lifting works in the trigger
callbacks is really something to avoid.


Ok, I redone this part and now the driver sets parameters for the device
in ops->prepare() if the substream was suspended. And everything works
fine. Thanks! I will send a new patch set soon.



Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-02 Thread Anton Yakovlev

On 02.03.2021 07:48, Takashi Iwai wrote:

On Tue, 02 Mar 2021 07:29:20 +0100,
Anton Yakovlev wrote:


On 28.02.2021 13:05, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:56 +0100,
Anton Yakovlev wrote:




[snip]


--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;


Actually you don't need to set SNDRV_PCM_INFO_RESUME.
This flag means that the driver supports the full resume procedure,
which isn't often the case; with this, the driver is supposed to
resume the stream exactly from the suspended position.

Most drivers don't set this but implement only the suspend-stop
action.  Then the application (or the sound backend) will re-setup the
stream and restart accordingly.


I tried to resume driver without SNDRV_PCM_INFO_RESUME, and alsa-lib
called only ops->prepare(). It makes sense for a typical hw, but we have
"clean" unconfigured device on resume. And we must set hw parameters as
a first step. It means, that code should be more or less the same. And
maybe it's better to set SNDRV_PCM_INFO_RESUME, since it allows us to
resume substream in any situation (regardless of application behavior).
I can refactor code to only send requests from trigger(RESUME) path and
not to call ops itself. It should make code more straitforward. What do
you say?


How about calling hw_params(NULL) conditionally in the prepare?


Then the question is that condition. When ops->prepare() is called, the
substream is in SUSPENDED state or not? If not then we need to track
this in some additional field (and it will make logic a little bit
clumsy, since that field is needed to be carefully handled in other
places).



Doing the full stack work in the trigger callback is bad from the API
design POV; in general the trigger callback is supposed to be as short
as possible.


Yeah, but usually original subsystem design does not take into account
para-virtualized devices, which usually have it's own slightly different
reality. And we need to introduce some tricks.




Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin




Re: [PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-02 Thread Anton Yakovlev

On 28.02.2021 13:05, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:56 +0100,
Anton Yakovlev wrote:




[snip]


--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
   SNDRV_PCM_INFO_BATCH |
   SNDRV_PCM_INFO_BLOCK_TRANSFER |
   SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME |
   SNDRV_PCM_INFO_PAUSE;


Actually you don't need to set SNDRV_PCM_INFO_RESUME.
This flag means that the driver supports the full resume procedure,
which isn't often the case; with this, the driver is supposed to
resume the stream exactly from the suspended position.

Most drivers don't set this but implement only the suspend-stop
action.  Then the application (or the sound backend) will re-setup the
stream and restart accordingly.


I tried to resume driver without SNDRV_PCM_INFO_RESUME, and alsa-lib
called only ops->prepare(). It makes sense for a typical hw, but we have
"clean" unconfigured device on resume. And we must set hw parameters as
a first step. It means, that code should be more or less the same. And
maybe it's better to set SNDRV_PCM_INFO_RESUME, since it allows us to
resume substream in any situation (regardless of application behavior).
I can refactor code to only send requests from trigger(RESUME) path and
not to call ops itself. It should make code more straitforward. What do
you say?


--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-01 Thread Anton Yakovlev

On 01.03.2021 14:38, Takashi Iwai wrote:

On Mon, 01 Mar 2021 11:03:04 +0100,
Anton Yakovlev wrote:


On 28.02.2021 13:05, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:56 +0100,
Anton Yakovlev wrote:


All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
   sound/virtio/virtio_card.c| 56 +++
   sound/virtio/virtio_pcm.c |  1 +
   sound/virtio/virtio_pcm_ops.c | 41 -
   3 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 59455a562018..c7ae8801991d 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -323,6 +323,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;
+
+ virtsnd_ctl_msg_cancel_all(snd);
+
+ vdev->config->del_vqs(vdev);
+ vdev->config->reset(vdev);
+
+ kfree(snd->event_msgs);
+
+ /*
+  * If the virtsnd_restore() fails before re-allocating events, then we
+  * get a dangling pointer here.
+  */
+ snd->event_msgs = NULL;
+
+ return 0;


I suppose some cancel of inflight works is needed?
Ditto for the device removal, too.


It's not necessary here, since the device is reset and all of this are
happened automatically.


Hrm, but the reset call itself might conflict with the inflight reset
work?  I haven't see any work canceling or flushing, so...


There maybe the following:

1. Some pending control requests -> these are cancelled in the
virtsnd_ctl_msg_cancel_all() call.

2. PCM messages -> these must not be cancelled, since they will be
requeued by driver on resume (starting with suspended position).

3. Some pending events from the device. These will be lost. Yeah, I
think we can process all pending events before destroying virtqueue.

Other that these, there are no other inflight works or so.



But in the device remove it makes sense also to
disable events before calling snd_card_free(), since the device is still
able to send notifications at that moment. Thanks!



--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;


Actually you don't need to set SNDRV_PCM_INFO_RESUME.
This flag means that the driver supports the full resume procedure,
which isn't often the case; with this, the driver is supposed to
resume the stream exactly from the suspended position.


If I understood you right, that's exactly how resume is implemented now
in the driver. Although we fully restart substream on the device side,
from an application point of view it is resumed exactly at the same
position.



Most drivers don't set this but implement only the suspend-stop
action.  Then the application (or the sound backend) will re-setup the
stream and restart accordingly.


And an application must be aware of such possible situation? Since I
have no doubt in alsa-lib, but I don't think that for example tinyalsa
can handle this right.


Tiny ALSA should work, too.  Actually there are only few drivers that
have the full PCM resume.  The majority of drivers are without the
resume support (including a large one like HD-audio).


Then it's a great news! Since we can simplify code a lot.



And, with the resume implementation, I'm worried by the style like:


@@ -309,6 +318,21 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream 
*substream, int command)
int rc;

switch (command) {
+ case SNDRV_PCM_TRIGGER_RESUME: {
+ /*
+  * We restart the substream by executing the standard command
+  * sequence.
+  */
+ rc = virtsnd_pcm_hw_params(substream, NULL);
+ if (rc)
+ return rc;
+
+ rc = virtsnd_pcm_prepare(substream);
+ if (rc)
+ return rc;


... and this is rather what the core code should do, and it's exactly
the same procedure that would be done without RESUME flag.


Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v6 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-03-01 Thread Anton Yakovlev

On 01.03.2021 15:56, Takashi Iwai wrote:

On Mon, 01 Mar 2021 15:47:46 +0100,
Anton Yakovlev wrote:


On 01.03.2021 14:32, Takashi Iwai wrote:

On Mon, 01 Mar 2021 10:25:05 +0100,
Anton Yakovlev wrote:


On 28.02.2021 12:27, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:52 +0100,
Anton Yakovlev wrote:

+/**
+ * virtsnd_pcm_event() - Handle the PCM device event notification.
+ * @snd: VirtIO sound device.
+ * @event: VirtIO sound event.
+ *
+ * Context: Interrupt context.


OK, then nonatomic PCM flag is invalid...


Well, no. Here, events are kind of independent entities. PCM-related
events are just a special case of more generic events, which can carry
any kind of notification/payload. (And at the moment, only XRUN
notification is supported for PCM substreams.) So it has nothing to do
with the atomicity of the PCM device itself.


OK, thanks.

Basically the only question is how snd_pcm_period_elapsed() is called.
And I see that it's called inside queue->lock, and this already
invalidates the nonatomic PCM mode.  So the code needs the fix: either
fix this locking (and the context is guaranteed not to be an irq
context), or change to the normal PCM mode without nonatomic flag.
Both would bring some side-effect, and we need further changes, I
suppose...


Ok, I understood the problem. Well, I would say the nonatomic PCM mode
is more important option, since in this mode we can guarantee the
correct operation of the device.


Which operation (except for the resume) in the trigger and the pointer
callbacks need the action that need to sleep?  I thought the sync with
the command queue is done in the sync_stop.  And most of others seem
already taking the spinlock in themselves, so the non-atomic operation
has little merit for them.


All three commands from the beginning of that switch in trigger op:
ops->trigger(START)
ops->trigger(PAUSE_RELEASE)
ops->trigger(RESUME)

They all result in
virtsnd_ctl_msg_send_sync(VIRTIO_SND_R_PCM_START)

And that command must be sync, i.e. we need to wait/sleep until device
sent response. There are two major reasons for that: we need to be sure,
that substream has been actually started (i.e. device said OK). And we
need to take into account the virtualization overhead as well. Since
substream starting on device side may take some time, we can not
return from the trigger op until it actually happened. In atomic mode
all these nuances are lost, and it may lead to incorrect application
behavior.



And if you say, that we need to get rid
of irq context here, then probably workqueue for calling
snd_pcm_period_elapsed() should be fine (of course, it should be shared
between all available substreams).


That would work, but it's of course just papering over it :)



+/**
+ * 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([idx]) + sgs[idx].length != page_to_phys(pg)) {
+ if (idx + 1 == nsgs)
+ break;
+ sg_set_page([++idx], pg, pg_length,
+ offset_in_page(data));
+ } else {
+  

Re: [PATCH v6 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-03-01 Thread Anton Yakovlev

On 01.03.2021 14:32, Takashi Iwai wrote:

On Mon, 01 Mar 2021 10:25:05 +0100,
Anton Yakovlev wrote:


On 28.02.2021 12:27, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:52 +0100,
Anton Yakovlev wrote:

+/**
+ * virtsnd_pcm_event() - Handle the PCM device event notification.
+ * @snd: VirtIO sound device.
+ * @event: VirtIO sound event.
+ *
+ * Context: Interrupt context.


OK, then nonatomic PCM flag is invalid...


Well, no. Here, events are kind of independent entities. PCM-related
events are just a special case of more generic events, which can carry
any kind of notification/payload. (And at the moment, only XRUN
notification is supported for PCM substreams.) So it has nothing to do
with the atomicity of the PCM device itself.


OK, thanks.

Basically the only question is how snd_pcm_period_elapsed() is called.
And I see that it's called inside queue->lock, and this already
invalidates the nonatomic PCM mode.  So the code needs the fix: either
fix this locking (and the context is guaranteed not to be an irq
context), or change to the normal PCM mode without nonatomic flag.
Both would bring some side-effect, and we need further changes, I
suppose...


Ok, I understood the problem. Well, I would say the nonatomic PCM mode
is more important option, since in this mode we can guarantee the
correct operation of the device. And if you say, that we need to get rid
of irq context here, then probably workqueue for calling
snd_pcm_period_elapsed() should be fine (of course, it should be shared
between all available substreams).



+/**
+ * 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([idx]) + sgs[idx].length != page_to_phys(pg)) {
+ if (idx + 1 == nsgs)
+ break;
+ sg_set_page([++idx], pg, pg_length,
+ offset_in_page(data));
+ } else {
+ sgs[idx].length += pg_length;
+ }
+
+ data += pg_length;
+ length -= pg_length;
+ }
+
+ sg_mark_end([idx]);
+}


Hmm, I thought there can be already a handy helper to convert vmalloc
to sglist, but apparently not.  It should have been trivial to get the
page list from vmalloc, e.g.

int vmalloc_to_page_list(void *p, struct page **page_ret)
{
  struct vmap_area *va;

  va = find_vmap_area((unsigned long)p);
  if (!va)
  return 0;
  *page_ret = va->vm->pages;
  return va->vm->nr_pages;
}

Then you can set up the sg list in a single call from the given page
list.

But it's just a cleanup, and let's mark it as a room for
improvements.


Yeah, we can take a look into some kind of optimizations here. But I
suspect, the overall code will look similar. It is not enough just to
get a list of pages, you also need to build a list of physically
contiguous regions from it.


I believe the standard helper does it.  But it's for sg_table, hence
the plain scatterlist needs to be extracted from there, but most of
complex things are in the standard code.

But it's m

Re: [PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-03-01 Thread Anton Yakovlev

On 28.02.2021 13:05, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:56 +0100,
Anton Yakovlev wrote:


All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
  sound/virtio/virtio_card.c| 56 +++
  sound/virtio/virtio_pcm.c |  1 +
  sound/virtio/virtio_pcm_ops.c | 41 -
  3 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 59455a562018..c7ae8801991d 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -323,6 +323,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;
+
+ virtsnd_ctl_msg_cancel_all(snd);
+
+ vdev->config->del_vqs(vdev);
+ vdev->config->reset(vdev);
+
+ kfree(snd->event_msgs);
+
+ /*
+  * If the virtsnd_restore() fails before re-allocating events, then we
+  * get a dangling pointer here.
+  */
+ snd->event_msgs = NULL;
+
+ return 0;


I suppose some cancel of inflight works is needed?
Ditto for the device removal, too.


It's not necessary here, since the device is reset and all of this are
happened automatically. But in the device remove it makes sense also to
disable events before calling snd_card_free(), since the device is still
able to send notifications at that moment. Thanks!



--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
   SNDRV_PCM_INFO_BATCH |
   SNDRV_PCM_INFO_BLOCK_TRANSFER |
   SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_RESUME |
   SNDRV_PCM_INFO_PAUSE;


Actually you don't need to set SNDRV_PCM_INFO_RESUME.
This flag means that the driver supports the full resume procedure,
which isn't often the case; with this, the driver is supposed to
resume the stream exactly from the suspended position.


If I understood you right, that's exactly how resume is implemented now
in the driver. Although we fully restart substream on the device side,
from an application point of view it is resumed exactly at the same
position.



Most drivers don't set this but implement only the suspend-stop
action.  Then the application (or the sound backend) will re-setup the
stream and restart accordingly.


And an application must be aware of such possible situation? Since I
have no doubt in alsa-lib, but I don't think that for example tinyalsa
can handle this right.



@@ -309,6 +318,21 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream 
*substream, int command)
   int rc;

   switch (command) {
+ case SNDRV_PCM_TRIGGER_RESUME: {
+ /*
+  * We restart the substream by executing the standard command
+  * sequence.
+  */
+ rc = virtsnd_pcm_hw_params(substream, NULL);
+ if (rc)
+ return rc;
+
+ rc = virtsnd_pcm_prepare(substream);
+ if (rc)
+ return rc;


And this won't work at all unless nonatomic PCM ops.


thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v6 6/9] ALSA: virtio: PCM substream operators

2021-03-01 Thread Anton Yakovlev

On 28.02.2021 12:32, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:53 +0100,
Anton Yakovlev wrote:





[snip]



+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(>lock, flags);
+ if (!vss->xfer_xrun)
+ hw_ptr = bytes_to_frames(substream->runtime, vss->hw_ptr);
+ spin_unlock_irqrestore(>lock, flags);


Oh, and if we drop nonatomc PCM, both trigger and pointer callbacks
are guaranteed to be called inside the spinlock, hence you can remove
*_irqsave() but just us spin_lock() in those two callbacks.


As I understand, spin_lock_irqsave() disables only local interrupts. But
what about other CPU cores?




thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v6 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-03-01 Thread Anton Yakovlev

On 28.02.2021 12:27, Takashi Iwai wrote:

On Sat, 27 Feb 2021 09:59:52 +0100,
Anton Yakovlev wrote:

+/**
+ * virtsnd_pcm_event() - Handle the PCM device event notification.
+ * @snd: VirtIO sound device.
+ * @event: VirtIO sound event.
+ *
+ * Context: Interrupt context.


OK, then nonatomic PCM flag is invalid...


Well, no. Here, events are kind of independent entities. PCM-related
events are just a special case of more generic events, which can carry
any kind of notification/payload. (And at the moment, only XRUN
notification is supported for PCM substreams.) So it has nothing to do
with the atomicity of the PCM device itself.



+/**
+ * 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([idx]) + sgs[idx].length != page_to_phys(pg)) {
+ if (idx + 1 == nsgs)
+ break;
+ sg_set_page([++idx], pg, pg_length,
+ offset_in_page(data));
+ } else {
+ sgs[idx].length += pg_length;
+ }
+
+ data += pg_length;
+ length -= pg_length;
+ }
+
+ sg_mark_end([idx]);
+}


Hmm, I thought there can be already a handy helper to convert vmalloc
to sglist, but apparently not.  It should have been trivial to get the
page list from vmalloc, e.g.

int vmalloc_to_page_list(void *p, struct page **page_ret)
{
 struct vmap_area *va;

 va = find_vmap_area((unsigned long)p);
 if (!va)
 return 0;
 *page_ret = va->vm->pages;
 return va->vm->nr_pages;
}

Then you can set up the sg list in a single call from the given page
list.

But it's just a cleanup, and let's mark it as a room for
improvements.


Yeah, we can take a look into some kind of optimizations here. But I
suspect, the overall code will look similar. It is not enough just to
get a list of pages, you also need to build a list of physically
contiguous regions from it. Because the sg-elements are put into a
virtqueue that has a limited size. And each sg-element consumes one item
in the virtqueue. And since the virtqueue itself is shared between all
substreams, the items of the virtqueue become a scarce resource.



(snip)

+/**
+ * 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 in

Re: [PATCH v6 3/9] ALSA: virtio: handling control messages

2021-02-28 Thread Anton Yakovlev
On 28.02.2021 12:04, Takashi Iwai wrote:> On Sat, 27 Feb 2021 09:59:50 
+0100,

Anton Yakovlev wrote:


--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -11,6 +11,10 @@

  #include "virtio_card.h"

+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");


If it's a global variable, better to set a prefix to make it unique,
and use module_param_named().


Yes, it makes sense.



And, it should be unsigned int, no? (unless a negative value has any meaning)
Otherwise...


And yes, it must be unsigned!



+ if (!msg_timeout_ms) {
+ dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+ return -EINVAL;


Here a negative value would pass.

(snip)

+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(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++] = >sg_request;
+ if (out_sgs)
+ psgs[nouts++] = out_sgs;
+
+ psgs[nouts + nins++] = >sg_response;
+ if (in_sgs)
+ psgs[nouts + nins++] = in_sgs;
+
+ spin_lock_irqsave(>lock, flags);
+ rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg,
+GFP_ATOMIC);


It's a bit pity that we have to use GFP_ATOMIC always here...
As long as it's in spinlock, it's the only way.


Well, here we have no other choices, since we share the queue with
an interrupt handler.



However, this reminds me of another question: may the virtio event be
handled in an atomic context, e.g. the period elapsed or xrun events?
If so, the current implementation with non-atomic PCM mode is wrong.
Since the non-atomic PCM uses mutex instead of spinlock, it'll lead to
a sleep-in-atomic in snd_pcm_period_elapsed() handling.

I suggested the non-atomic PCM *iff* the all contexts are sleepable;
then the sync can be done in each callback, which makes the code much
simpler usually.  But you've already implemented the sync via
sync_stop call, hence the non-atomic PCM has little benefit by its
own.


The device provides 4 separate queues for communication with the driver,
and different data is transmitted over these queues:

The control queue (actually shared between all driver components) for
sending commands to the device. These requests must be synchronous. For
each request, the device must send a response, and we must wait for it.
What you can see in PCM ops are exactly sending these commands (set
params, prepare, start and so on). But since some ops could be called in
atomic context, there was no other choice but to add asynchronous
messages and return from the operator without waiting for a response
from the device. Because of this, the START command was a headache. We
could not say for sure if the substream started at all on the device
side. Also, the virtualization overhead was not taken into account
(application might think that the substream is already running, but
actually it was not).

Then there are 2 queues for sending/receiving PCM frames. These contain
i/o messages carrying actual buffer sliced into periods. Actually,
snd_pcm_period_elapsed() is called from interrupt handlers here.

And then there is an additional queue for events.

All of these are handled in different ways.




thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



[PATCH v6 8/9] ALSA: virtio: introduce PCM channel map support

2021-02-27 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 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 c852afda5712..59455a562018 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -197,6 +197,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)
@@ -209,6 +213,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 2092da297a9d..6af3d4816f57 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 ..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 
+
+#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() -

[PATCH v6 9/9] ALSA: virtio: introduce device suspend/resume support

2021-02-27 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/virtio_card.c| 56 +++
 sound/virtio/virtio_pcm.c |  1 +
 sound/virtio/virtio_pcm_ops.c | 41 -
 3 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 59455a562018..c7ae8801991d 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -323,6 +323,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;
+
+   virtsnd_ctl_msg_cancel_all(snd);
+
+   vdev->config->del_vqs(vdev);
+   vdev->config->reset(vdev);
+
+   kfree(snd->event_msgs);
+
+   /*
+* If the virtsnd_restore() fails before re-allocating events, then we
+* get a dangling pointer here.
+*/
+   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 },
@@ -335,6 +387,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.c b/sound/virtio/virtio_pcm.c
index 3605151860f2..4a4a6583b002 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index d02d79bd94f3..03a7e2666cfb 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -167,7 +167,8 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream 
*substream,
int vrate = -1;
int rc;
 
-   if (virtsnd_pcm_msg_pending_num(vss)) {
+   if (runtime->status->state != SNDRV_PCM_STATE_SUSPENDED &&
+   virtsnd_pcm_msg_pending_num(vss)) {
dev_err(>dev, "SID %u: invalid I/O queue state\n",
vss->sid);
return -EBADFD;
@@ -231,6 +232,10 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream 
*substream,
if (rc)
return rc;
 
+   /* If messages have already been allocated before, do nothing. */
+   if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
+   return 0;
+
/* Free previously allocated messages (if any). */
virtsnd_pcm_msg_free(vss);
 
@@ -267,20 +272,24 @@ static int virtsnd_pcm_hw_free(struct snd_pcm_substream 
*substream)
  */
 static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
 {
+   struct snd_pcm_runtime *runtime = substream->runtime;
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(>dev, "SID %u: invalid I/O queue state\n",
-   vss->sid);
-   return -EBADFD;
+   if (runtime->status->state != SNDRV_PCM_STATE_SUSPENDED) {
+   if (virtsnd_pcm_msg_pending_num(vss)) {
+   dev_err(>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;
}
 
-   vss->buffer_bytes = snd_pcm_lib_buffer_byte

[PATCH v6 7/9] ALSA: virtio: introduce jack support

2021-02-27 Thread Anton Yakovlev
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 
---
 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 9f74261b234c..c852afda5712 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -67,6 +67,10 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
virtqueue_disable_cb(vqueue);
while ((event = virtqueue_get_buf(vqueue, ))) {
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);
@@ -185,10 +189,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 7e50f3835ab1..2092da297a9d 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 ..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 
+#include 
+#include 
+
+#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 ja

[PATCH v6 6/9] ALSA: virtio: PCM substream operators

2021-02-27 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_pcm.c |   2 +
 sound/virtio/virtio_pcm.h |   4 +
 sound/virtio/virtio_pcm_ops.c | 453 ++
 4 files changed, 461 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 3cfd3520a9c0..3605151860f2 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -454,6 +454,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, _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 7af41cad4e8f..55dfb19d14b3 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -28,6 +28,7 @@ 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).
+ * @release: True if the substream 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.
@@ -47,6 +48,7 @@ struct virtio_pcm_substream {
size_t hw_ptr;
bool xfer_enabled;
bool xfer_xrun;
+   bool release;
struct virtio_pcm_msg **msgs;
unsigned int nmsgs;
int msg_last_enqueued;
@@ -78,6 +80,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 ..d02d79bd94f3
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+
+#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 },
+ 

[PATCH v6 2/9] ALSA: virtio: add virtio sound driver

2021-02-27 Thread Anton Yakovlev
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 
---
 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  | 289 +++
 sound/virtio/virtio_card.h  |  65 +++
 8 files changed, 718 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 c71664ca8bfd..4369946434ad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19049,6 +19049,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..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 
+
+/***
+ * 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 

[PATCH v6 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-02-27 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  18 +-
 sound/virtio/virtio_card.h|   9 +
 sound/virtio/virtio_pcm.c |  32 +++
 sound/virtio/virtio_pcm.h |  40 
 sound/virtio/virtio_pcm_msg.c | 417 ++
 6 files changed, 516 insertions(+), 3 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 c5e9ceaaa8a0..9f74261b234c 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -65,8 +65,16 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
spin_lock_irqsave(>lock, flags);
do {
virtqueue_disable_cb(vqueue);
-   while ((event = virtqueue_get_buf(vqueue, )))
+   while ((event = virtqueue_get_buf(vqueue, ))) {
+   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;
+   }
+
virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
+   }
if (unlikely(virtqueue_is_broken(vqueue)))
break;
} while (!virtqueue_enable_cb(vqueue));
@@ -87,7 +95,9 @@ 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",
@@ -273,6 +283,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_ctl_msg_cancel_all(snd);
 
@@ -282,6 +293,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)
+   virtsnd_pcm_msg_free(>substreams[i]);
+
kfree(snd->event_msgs);
 }
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 4431cc8f0445..7e50f3835ab1 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 >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 4348ead63c14..3cfd3520a9c0 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -337,6 +337,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
 
vss->snd = snd;
vss->sid = i;
+   init_waitqueue_head(>msg_empty);
+   spin_lock_init(>lock);
 
rc = virtsnd_pcm_build_hw(vss, [i]);
if (rc)
@@ -461,3 +463,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 

[PATCH v6 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-02-27 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   3 +-
 sound/virtio/virtio_card.c |  14 ++
 sound/virtio/virtio_card.h |  10 +
 sound/virtio/virtio_pcm.c  | 463 +
 sound/virtio/virtio_pcm.h  |  70 ++
 5 files changed, 559 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 196cb97087b0..c5e9ceaaa8a0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -175,6 +175,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);
 }
 
@@ -203,6 +213,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (virtsnd_pcm_validate(vdev))
+   return -EINVAL;
+
return 0;
 }
 
@@ -225,6 +238,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
 
snd->vdev = vdev;
INIT_LIST_HEAD(>ctl_msgs);
+   INIT_LIST_HEAD(>pcm_list);
 
vdev->priv = snd;
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 349311a30199..4431cc8f0445 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -12,9 +12,13 @@
 #include 
 
 #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 ..4348ead63c14
--- /dev/null
+++ b/sound/virtio/virtio_pcm.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+#include 
+
+#include "virtio_card.h"
+
+static unsigned int pcm_buffer_ms = 160;
+module_param(pcm_buffer_ms, uint, 0644);
+MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds");
+
+static unsigned int pcm_periods_min = 2;
+module_param(pcm_periods_min, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods");
+
+static unsigned int pcm_periods_max = 16;
+module_param(pcm_periods_max, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods");
+
+static unsigned int 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 unsigned int 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] 

[PATCH v6 3/9] ALSA: virtio: handling control messages

2021-02-27 Thread Anton Yakovlev
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 
---
 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 697cb5f16e4d..196cb97087b0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -11,6 +11,10 @@
 
 #include "virtio_card.h"
 
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
 static void virtsnd_remove(struct virtio_device *vdev);
 
 /**
@@ -82,6 +86,7 @@ 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] = {
@@ -193,6 +198,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (!msg_timeout_ms) {
+   dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+   return -EINVAL;
+   }
+
return 0;
 }
 
@@ -214,6 +224,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
return -ENOMEM;
 
snd->vdev = vdev;
+   INIT_LIST_HEAD(>ctl_msgs);
 
vdev->priv = snd;
 
@@ -249,6 +260,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
 {
struct virtio_snd *snd = vdev->priv;
 
+   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..349311a30199 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -11,6 +11,8 @@
 #include 
 #include 
 
+#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 int 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 ..67a5a0301ba3
--- /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 
+#include 
+
+#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(>ref_count);
+}
+
+/**
+ * virtsnd_ctl_msg_unref() - Decrement reference counter for the message.
+ * @msg: Control message.
+ *
+ * 

[PATCH v6 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-02-27 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.1




Re: [PATCH v5 6/9] ALSA: virtio: PCM substream operators

2021-02-26 Thread Anton Yakovlev
On 25.02.2021 21:30, Takashi Iwai wrote:> On Thu, 25 Feb 2021 20:02:50 
+0100,

Michael S. Tsirkin wrote:




[snip]


If you want to merge it yourself instead, also please say so.


I don't mind who take the patches, although it looks more fitting to
merge through sound git tree if judging from the changes put in
sound/* directory.


Then should I update the MAINTAINERS and add Takashi instead of
Michael, or should I put both of you there?


--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v5 6/9] ALSA: virtio: PCM substream operators

2021-02-26 Thread Anton Yakovlev

On 26.02.2021 15:23, Takashi Iwai wrote:

On Thu, 25 Feb 2021 23:19:31 +0100,
Anton Yakovlev wrote:


On 25.02.2021 21:30, Takashi Iwai wrote:> On Thu, 25 Feb 2021 20:02:50
+0100,

Michael S. Tsirkin wrote:


On Thu, Feb 25, 2021 at 01:51:16PM +0100, Takashi Iwai wrote:

On Thu, 25 Feb 2021 13:14:37 +0100,
Anton Yakovlev wrote:



[snip]



Takashi given I was in my tree for a while and I planned to merge
it this merge window.


Hmm, that's too quick, I'm afraid.  I see still a few rough edges in
the code.  e.g. the reset work should be canceled at the driver
removal, but it's missing right now.  And that'll become tricky
because the reset work itself unbinds the device, hence it'll get
stuck if calling cancel_work_sync() at remove callback.


Yes, you made a good point here! In this case, we need some external
mutex for synchronization. This is just a rough idea, but maybe
something like this might work:

struct reset_work {
 struct mutex mutex;
 struct work_struct work;
 struct virtio_snd *snd;
 bool resetting;
};

static struct reset_work reset_works[SNDRV_CARDS];

init()
 // init mutexes and workers


virtsnd_probe()
 snd_card_new(snd->card)
 reset_works[snd->card->number].snd = snd;


virtsnd_remove()
 mutex_lock(reset_works[snd->card->number].mutex)
 reset_works[snd->card->number].snd = NULL;
 resetting = reset_works[snd->card->number].resetting;
 mutex_unlock(reset_works[snd->card->number].mutex)

 if (!resetting)
 // cancel worker reset_works[snd->card->number].work
 // remove device


virtsnd_reset_fn(work)
 mutex_lock(work->mutex)
 if (!work->snd)
 // do nothing and take an exit path
 work->resetting = true;
 mutex_unlock(work->mutex)

 device_reprobe()

 work->resetting = false;


interrupt_handler()
 schedule_work(reset_works[snd->card->number].work);


What do you think?


I think it's still somehow racy.  Suppose that the reset_work is
already running right before entering virtsnd_remove(): it sets
reset_works[].resetting flag, virtsnd_remove() skips canceling, and
both reset work and virtsnd_remove() perform at the very same time.
(I don't know whether this may happen, but I assume it's possible.)

In that case, maybe a better check is to check current_work(), and
perform cancel_work_sync() unless it's _works[].work itself.
Then the recursive cancel call can be avoided.

After that point, the reset must be completed, and we can (again)
process the rest release procedure.  (But also snd object itself might
have been changed again, so it needs to be re-evaluated.)

One remaining concern is that the card number of the sound instance
may change after reprobe.  That is, we may want to another persistent
object instead of accessing via an array index of sound card number.
So, we might need reset_works[] associated with virtio_snd object
instead.

In anyway, this is damn complex.  I sincerely hope that we can avoid
this kind of things.  Wouldn't it be better to shift the reset stuff
up to the virtio core layer?  Or drop the feature in the first
version.  Shooting itself (and revival) is a dangerous magic spell,
after all.


Yes, I also got an impression, that without some assistance somewhere
from the bus it will hardly be possible to find a suitable solution.
Ok, then I will postpone this feature at the moment.




thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: NFS Caching broken in 4.19.37

2021-02-26 Thread Anton Ivanov

On 26/02/2021 15:03, Timo Rothenpieler wrote:
I think I can reproduce this, or something that at least looks very 
similar to this, on 5.10. Namely on 5.10.17 (On both Client and Server).


I think this is a different issue - see below.



We are running slurm, and since a while now (coincides with updating 
from 5.4 to 5.10, but a whole bunch of other stuff was updated at the 
same time, so it took me a while to correlate this) the logs it writes 
have been truncated, but only while they're being observed on the 
client, using tail -f or something like that.


Looks like this then:

On Server:

store01 /srv/export/home/users/timo/TestRun # ls -l slurm-41101.out
-rw-r--r-- 1 timo timo 1931 Feb 26 15:46 slurm-41101.out
store01 /srv/export/home/users/timo/TestRun # wc -l slurm-41101.out
61 slurm-41101.out


On Client:

timo@login01 ~/TestRun $ ls -l slurm-41101.out
-rw-r--r-- 1 timo timo 1931 Feb 26 15:46 slurm-41101.out
timo@login01 ~/TestRun $ wc -l slurm-41101.out
24 slurm-41101.out


See https://gist.github.com/BtbN/b9eb4fc08ccc53bb20087bce0bf9f826 for 
the respective file-contents.


If I run the same test job, wait until its done, and then look at its 
slurm.out file, it matches between NFS Client and Server.
If I tail -f the slurm.out on an NFS client, the file stops getting 
updated on the client, but keeps getting more logs written to it on 
the NFS server.


The slurm.out file is being written to by another NFS client, which is 
running on one of the compute nodes of the system. It's being reads 
from a login node.


These are two different clients, then what you see is possible on NFS 
with client side caching. If you have multiple clients reading/writing 
to the same files you usually need to tune the caching options and/or 
use locking. I suspect that if you leave it for a while (until the cache 
expires) it will sort itself out.


In my test-case it is just one client, it missed a file deletion and 
nothing short of an unmount and remount fixes that. I have waited for 30 
mins+. It does not seem to refresh or expire. I also see the opposite 
behavior - the bug shows up on 4.x up to at least 5.4. I do not see it 
on 5.10.


Brgds,







Timo


On 21.02.2021 16:53, Anton Ivanov wrote:

Client side. This seems to be an entirely client side issue.

A variety of kernels on the clients starting from 4.9 and up to 5.10 
using 4.19 servers. I have observed it on a 4.9 client versus 4.9 
server earlier.


4.9 fails, 4.19 fails, 5.2 fails, 5.4 fails, 5.10 works.

At present the server is at 4.19.67 in all tests.

Linux jain 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 
(2019-11-11) x86_64 GNU/Linux


I can set-up a couple of alternative servers during the week, but so 
far everything is pointing towards a client fs cache issue, not a 
server one.


Brgds,






--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/



Re: [PATCH v5 6/9] ALSA: virtio: PCM substream operators

2021-02-25 Thread Anton Yakovlev
On 25.02.2021 21:30, Takashi Iwai wrote:> On Thu, 25 Feb 2021 20:02:50 
+0100,

Michael S. Tsirkin wrote:


On Thu, Feb 25, 2021 at 01:51:16PM +0100, Takashi Iwai wrote:

On Thu, 25 Feb 2021 13:14:37 +0100,
Anton Yakovlev wrote:



[snip]



Takashi given I was in my tree for a while and I planned to merge
it this merge window.


Hmm, that's too quick, I'm afraid.  I see still a few rough edges in
the code.  e.g. the reset work should be canceled at the driver
removal, but it's missing right now.  And that'll become tricky
because the reset work itself unbinds the device, hence it'll get
stuck if calling cancel_work_sync() at remove callback.


Yes, you made a good point here! In this case, we need some external
mutex for synchronization. This is just a rough idea, but maybe
something like this might work:

struct reset_work {
struct mutex mutex;
struct work_struct work;
struct virtio_snd *snd;
bool resetting;
};

static struct reset_work reset_works[SNDRV_CARDS];

init()
// init mutexes and workers


virtsnd_probe()
snd_card_new(snd->card)
reset_works[snd->card->number].snd = snd;


virtsnd_remove()
mutex_lock(reset_works[snd->card->number].mutex)
reset_works[snd->card->number].snd = NULL;
resetting = reset_works[snd->card->number].resetting;
mutex_unlock(reset_works[snd->card->number].mutex)

if (!resetting)
// cancel worker reset_works[snd->card->number].work
// remove device


virtsnd_reset_fn(work)
mutex_lock(work->mutex)
if (!work->snd)
// do nothing and take an exit path
work->resetting = true;
mutex_unlock(work->mutex)

device_reprobe()

work->resetting = false;


interrupt_handler()
schedule_work(reset_works[snd->card->number].work);


What do you think?


--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v5 6/9] ALSA: virtio: PCM substream operators

2021-02-25 Thread Anton Yakovlev

On 25.02.2021 11:55, Takashi Iwai wrote:

On Mon, 22 Feb 2021 16:34:41 +0100,
Anton Yakovlev wrote:

+static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream);
+ struct virtio_pcm_substream *vss = NULL;
+
+ if (vpcm) {
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ case SNDRV_PCM_STREAM_CAPTURE: {


The switch() here looks superfluous.  The substream->stream must be a
good value in the callback.  If any, you can put WARN_ON() there, but
I don't think it worth.


At least it doesn't do any harm. If something really went wrong, we can
check it right in the open callback, which is called the very first.



+static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream,
+  struct snd_pcm_hw_params *hw_params)
+{



+ return virtsnd_pcm_msg_alloc(vss, periods, period_bytes);


We have the allocation, but...


+static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return 0;


... no release at hw_free()?
I know that the free is present in the allocator, but it's only for
re-allocation case, I suppose.


When the substream stops, sync_ptr 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 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 either in hw_params() or in
dev->release(), since there it is 100% safe.



thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v5 2/9] ALSA: virtio: add virtio sound driver

2021-02-25 Thread Anton Yakovlev

On 25.02.2021 11:38, Takashi Iwai wrote:

On Mon, 22 Feb 2021 16:34:37 +0100,
Anton Yakovlev wrote:

+static int virtsnd_find_vqs(struct virtio_snd *snd)
+{
+ struct virtio_device *vdev = snd->vdev;
+ vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
+ [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
+ };
+ const char *names[VIRTIO_SND_VQ_MAX] = {


Shouldn't be static?


Well, yes. Although in this particular case, I do not think it is that
critical. :)



Also it's often const char * const names[] = { ... }
unless you overwrite something.


I tried to use the same type names as in the function prototype.
Otherwise the compiler or static analyzer may complain.



+/**
+ * virtsnd_reset_fn() - Kernel worker's function to reset the device.
+ * @work: Reset device work.
+ *
+ * Context: Process context.
+ */
+static void virtsnd_reset_fn(struct work_struct *work)
+{
+ struct virtio_snd *snd =
+ container_of(work, struct virtio_snd, reset_work);
+ struct virtio_device *vdev = snd->vdev;
+ struct device *dev = >dev;
+ int rc;
+
+ dev_info(dev, "sound device needs reset\n");
+
+ /*
+  * It seems that the only way to properly reset the device is to remove
+  * and re-create the ALSA sound card device.
+  */
+ rc = device_reprobe(dev);
+ if (rc)
+ dev_err(dev, "failed to reprobe sound device: %d\n", rc);


Now I'm wondering whether it's safe to do that from this place.
Basically device_reprobe() unbinds the device that releases the full
resources once including the devm_* stuff.  And this work itself is in
a part of devm allocated resource, so it'll be released there.  That
said, we might hit use-after-free...  This needs to be verified.


It's safe. Suicide kernel workers are funny but possible things. Since
the kernel itself (AFAIU) assumes such a situation and does not access
the worker structure after the callback function call.



thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



[PATCH v5 9/9] ALSA: virtio: introduce device suspend/resume support

2021-02-22 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/virtio_card.c| 57 +++
 sound/virtio/virtio_pcm.c |  1 +
 sound/virtio/virtio_pcm_ops.c | 44 ---
 3 files changed, 91 insertions(+), 11 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 787a4dec1da8..1f0a0fa7bbc0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -373,6 +373,59 @@ static void virtsnd_config_changed(struct virtio_device 
*vdev)
 "sound device configuration was changed\n");
 }
 
+#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;
+
+   /* Stop all the virtqueues. */
+   vdev->config->reset(vdev);
+   vdev->config->del_vqs(vdev);
+
+   virtsnd_ctl_msg_cancel_all(snd);
+
+   kfree(snd->event_msgs);
+
+   /*
+* If the virtsnd_restore() fails before re-allocating events, then we
+* get a dangling pointer here.
+*/
+   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 },
@@ -386,6 +439,10 @@ static struct virtio_driver virtsnd_driver = {
.probe = virtsnd_probe,
.remove = virtsnd_remove,
.config_changed = virtsnd_config_changed,
+#ifdef CONFIG_PM_SLEEP
+   .freeze = virtsnd_freeze,
+   .restore = virtsnd_restore,
+#endif
 };
 
 static int __init init(void)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 3605151860f2..4a4a6583b002 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index 07510778b555..ccef64502c13 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -218,6 +218,10 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream 
*substream,
if (rc)
return rc;
 
+   /* If messages have already been allocated before, do nothing. */
+   if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
+   return 0;
+
return virtsnd_pcm_msg_alloc(vss, periods, period_bytes);
 }
 
@@ -258,19 +262,21 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream 
*substream)
}
 
spin_lock_irqsave(>lock, flags);
-   /*
-* Since I/O messages are asynchronous, they can be completed
-* when the runtime structure no longer exists. Since each
-* completion implies incrementing the hw_ptr, we cache all the
-* current values needed to compute the new hw_ptr value.
-*/
-   vss->frame_bytes = runtime->frame_bits >> 3;
-   vss->period_size = runtime->period_size;
-   vss->buffer_size = runtime->buffer_size;
+   if (runtime->status->state != SNDRV_PCM_STATE_SUSPENDED) {
+   /*
+* Since I/O messages are asynchronous, they can be completed
+* when the runtime structure no longer exists. Since each
+* completion implies incrementing the hw_ptr, we cache all the
+* current values needed to compute the new hw_ptr value.
+*/
+   vss->frame_bytes = runtime->frame_bits >> 3;
+   vss->period_size = runtime->period_size;
+   vss->buffer_size = runtime->buffer_size;
 
-   vss->hw_ptr = 0;
+   vss->hw_ptr = 0;
+   vss->msg_last_enqueued = -1;
+   }
vss->xfer_xrun = false;
-   vss->msg_last_enqueued = -1;
vss->msg_count = 0;
spin_unlock_irqrestore(>lock, flags);
 
@@ -300,6 +306

[PATCH v5 6/9] ALSA: virtio: PCM substream operators

2021-02-22 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_pcm.c |   2 +
 sound/virtio/virtio_pcm.h |   4 +
 sound/virtio/virtio_pcm_ops.c | 469 ++
 4 files changed, 477 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 3cfd3520a9c0..3605151860f2 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -454,6 +454,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, _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 c70e4fed9044..c48d00acee2e 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -35,6 +35,7 @@ struct virtio_pcm_msg;
  * @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.
+ * @msg_flushing: True if the I/O queue is in flushing state.
  */
 struct virtio_pcm_substream {
struct virtio_snd *snd;
@@ -56,6 +57,7 @@ struct virtio_pcm_substream {
int msg_last_enqueued;
unsigned int msg_count;
wait_queue_head_t msg_empty;
+   bool msg_flushing;
 };
 
 /**
@@ -82,6 +84,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 ..07510778b555
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+
+#include "virtio_card.h"
+
+/* 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 },
+   { 4

[PATCH v5 8/9] ALSA: virtio: introduce PCM channel map support

2021-02-22 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 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 4578d0ce0726..787a4dec1da8 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -222,6 +222,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)
@@ -234,6 +238,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 37896a030e10..817508b3e9b4 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -44,6 +44,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;
@@ -57,6 +59,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). */
@@ -102,4 +106,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 ..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 
+
+#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() -

[PATCH v5 7/9] ALSA: virtio: introduce jack support

2021-02-22 Thread Anton Yakovlev
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 
---
 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 a845978111d6..4578d0ce0726 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -67,6 +67,10 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
virtqueue_disable_cb(vqueue);
while ((event = virtqueue_get_buf(vqueue, ))) {
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);
@@ -210,10 +214,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 3d8f5ad92f79..37896a030e10 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;
 
 /**
@@ -39,6 +40,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.
  */
@@ -50,6 +53,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;
 };
@@ -90,4 +95,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 ..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 
+#include 
+#include 
+
+#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 ja

[PATCH v5 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-02-22 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  18 +-
 sound/virtio/virtio_card.h|   9 +
 sound/virtio/virtio_pcm.c |  32 +++
 sound/virtio/virtio_pcm.h |  42 
 sound/virtio/virtio_pcm_msg.c | 392 ++
 6 files changed, 493 insertions(+), 3 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 235afc25fce7..a845978111d6 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -65,8 +65,16 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
spin_lock_irqsave(>lock, flags);
do {
virtqueue_disable_cb(vqueue);
-   while ((event = virtqueue_get_buf(vqueue, )))
+   while ((event = virtqueue_get_buf(vqueue, ))) {
+   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;
+   }
+
virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
+   }
if (unlikely(virtqueue_is_broken(vqueue)))
break;
} while (!virtqueue_enable_cb(vqueue));
@@ -87,7 +95,9 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
struct virtio_device *vdev = snd->vdev;
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
};
const char *names[VIRTIO_SND_VQ_MAX] = {
[VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
@@ -299,6 +309,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;
 
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
@@ -310,6 +321,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
 
vdev->config->del_vqs(vdev);
 
+   for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
+   virtsnd_pcm_msg_free(>substreams[i]);
+
kfree(snd->event_msgs);
 }
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index f5e06a1ec033..3d8f5ad92f79 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -81,4 +81,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
return >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 4348ead63c14..3cfd3520a9c0 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -337,6 +337,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
 
vss->snd = snd;
vss->sid = i;
+   init_waitqueue_head(>msg_empty);
+   spin_lock_init(>lock);
 
rc = virtsnd_pcm_build_hw(vss, [i]);
if (rc)
@@ -461,3 +463,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 virt

[PATCH v5 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-02-22 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   3 +-
 sound/virtio/virtio_card.c |  14 ++
 sound/virtio/virtio_card.h |  10 +
 sound/virtio/virtio_pcm.c  | 463 +
 sound/virtio/virtio_pcm.h  |  70 ++
 5 files changed, 559 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 c62b3a2da148..235afc25fce7 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -200,6 +200,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);
 }
 
@@ -228,6 +238,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (virtsnd_pcm_validate(vdev))
+   return -EINVAL;
+
return 0;
 }
 
@@ -251,6 +264,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
INIT_LIST_HEAD(>ctl_msgs);
+   INIT_LIST_HEAD(>pcm_list);
 
vdev->priv = snd;
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index c51a71a79388..f5e06a1ec033 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -12,9 +12,13 @@
 #include 
 
 #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.
@@ -34,6 +38,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;
@@ -42,6 +49,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 ..4348ead63c14
--- /dev/null
+++ b/sound/virtio/virtio_pcm.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+#include 
+
+#include "virtio_card.h"
+
+static unsigned int pcm_buffer_ms = 160;
+module_param(pcm_buffer_ms, uint, 0644);
+MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds");
+
+static unsigned int pcm_periods_min = 2;
+module_param(pcm_periods_min, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods");
+
+static unsigned int pcm_periods_max = 16;
+module_param(pcm_periods_max, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods");
+
+static unsigned int 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 unsigned int 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_

[PATCH v5 2/9] ALSA: virtio: add virtio sound driver

2021-02-22 Thread Anton Yakovlev
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. Also, handling DEVICE_NEEDS_RESET device
status.

Signed-off-by: Anton Yakovlev 
---
 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  | 340 
 sound/virtio/virtio_card.h  |  67 +++
 8 files changed, 771 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 bfc1b86e3e73..599c1231214d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18945,6 +18945,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..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 
+
+/***
+ * 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) */
+  

[PATCH v5 3/9] ALSA: virtio: handling control messages

2021-02-22 Thread Anton Yakovlev
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 
---
 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 b5f63b5b7db4..c62b3a2da148 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -11,6 +11,10 @@
 
 #include "virtio_card.h"
 
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
 static void virtsnd_remove(struct virtio_device *vdev);
 
 /**
@@ -82,6 +86,7 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
 {
struct virtio_device *vdev = snd->vdev;
vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
+   [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
};
const char *names[VIRTIO_SND_VQ_MAX] = {
@@ -218,6 +223,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (!msg_timeout_ms) {
+   dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+   return -EINVAL;
+   }
+
return 0;
 }
 
@@ -240,6 +250,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
 
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
+   INIT_LIST_HEAD(>ctl_msgs);
 
vdev->priv = snd;
 
@@ -278,6 +289,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
 
+   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 244381cc7a9b..c51a71a79388 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -11,6 +11,8 @@
 #include 
 #include 
 
+#include "virtio_ctl_msg.h"
+
 #define VIRTIO_SND_CARD_DRIVER "virtio-snd"
 #define VIRTIO_SND_CARD_NAME   "VirtIO SoundCard"
 
@@ -30,6 +32,7 @@ struct virtio_snd_queue {
  * @queues: Virtqueue wrappers.
  * @reset_work: Reset device work.
  * @card: ALSA sound card.
+ * @ctl_msgs: Pending control request list.
  * @event_msgs: Device events.
  */
 struct virtio_snd {
@@ -37,9 +40,13 @@ struct virtio_snd {
struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
struct work_struct reset_work;
struct snd_card *card;
+   struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
 };
 
+/* Message completion timeout in milliseconds (module parameter). */
+extern int 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 ..67a5a0301ba3
--- /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 
+#include 
+
+#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(>ref_count);
+}
+
+/**
+ * virtsnd_ctl_msg_unref() - Decrement reference c

[PATCH v5 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-02-22 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.0




Re: [PATCH] ARM: dts: nuvoton: Fix flash layout

2021-02-22 Thread Anton Kachalov
Ofer,

The oldest version from igps doesn't work as well as the latest
version from u-boot github.

The only version that works for me is in software deliverables:

https://github.com/Nuvoton-Israel/nuvoton-info/tree/master/npcm7xx-poleg/evaluation-board/sw_deliverables/npcm7xx_v2.3

On Mon, 22 Feb 2021 at 15:10, IS20 Ofer Eilon  wrote:
>
> Hi Avi,
>
> It seems an old version of uboot  u-boot_2019.01.7.5.bin  from igps below:
>
> > https://apc01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FNuvoton-Israel%2Figps%2Ftree%2Fmaster%2FImageGeneration%2Fversionsdata=04%7C01%7Cofer.eilon%40nuvoton.com%7Ce56881b8491d42e5ee4c08d8d71bacd4%7Ca3f24931d4034b4a94f17d83ac638e07%7C0%7C0%7C637495861162860437%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=0%2BNzEv%2FSX9QTg0XumchRrU61uGbZ3CZXrtspXu2560I%3Dreserved=0
>
> Please use latest from uboot.bin github.
>
> Regards,
> Ofer
>
>
> -Original Message-
> From: Avi Fishman 
> Sent: Monday, February 22, 2021 12:21 PM
> To: Anton Kachalov 
> Cc: Tomer Maimon ; Benjamin Fair 
> ; Tali Perry ; Patrick 
> Venture ; Nancy Yuen ; Rob Herring 
> ; OpenBMC Maillist ; devicetree 
> ; Linux Kernel Mailing List 
> ; IS20 Ofer Eilon 
> Subject: Re: [PATCH] ARM: dts: nuvoton: Fix flash layout
>
> Ofer,
>
> Can you check why u-boot doesn't work with SD cards?
>
> On Mon, Feb 22, 2021 at 11:27 AM Anton Kachalov  wrote:
> >
> > Hi, Tom.
> >
> > Yes, I'm using it for testing on real hardware.
> >
> > BTW. Recent u-boot doesn't work with SD cards. The card doesn't
> > detect. The last working version was this one:
> >
> > https://apc01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgith
> > ub.com%2FNuvoton-Israel%2Fnuvoton-info%2Ftree%2Fmaster%2Fnpcm7xx-poleg
> > %2Fevaluation-board%2Fsw_deliverables%2Fnpcm7xx_v2.3data=04%7C01%
> > 7Cofer.eilon%40nuvoton.com%7Ce56881b8491d42e5ee4c08d8d71bacd4%7Ca3f249
> > 31d4034b4a94f17d83ac638e07%7C0%7C0%7C637495861162860437%7CUnknown%7CTW
> > FpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6
> > Mn0%3D%7C1000sdata=f4t41g3CQaFTQNfwwNVBrIwQScndIGcfRTms0yrTn5o%3D
> > reserved=0
> >
> > However, u-boot from igps repo:
> >
> > https://apc01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgith
> > ub.com%2FNuvoton-Israel%2Figps%2Ftree%2Fmaster%2FImageGeneration%2Fver
> > sionsdata=04%7C01%7Cofer.eilon%40nuvoton.com%7Ce56881b8491d42e5ee
> > 4c08d8d71bacd4%7Ca3f24931d4034b4a94f17d83ac638e07%7C0%7C0%7C6374958611
> > 62860437%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiL
> > CJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=0%2BNzEv%2FSX9QTg0Xumch
> > RrU61uGbZ3CZXrtspXu2560I%3Dreserved=0
> >
> > Has issues too. It doesn't allow me to read more than 4k bytes once at
> > a time. Thus, to flash the stuff I have manually read chunks from the
> > SD-card: fat load doesn't work at all and I write that data in raw
> > partition.
> >
> > On Sun, 21 Feb 2021 at 17:40, Tomer Maimon  wrote:
> > >
> > > Hi Benjamin and Anton,
> > >
> > > Sorry for the late reply,
> > >
> > > The EVB FIU0-CS0 partitioning is used for testing the EVB and this is why 
> > > it is different than the OpenBMC flash layout.
> > >
> > >
> > >
> > > Are you using the NPCM7XX EVB for OpenBMC? if yes we can consider to 
> > > modify the flash partition to OpenBMC use.
> > >
> > >
> > > On Thu, 18 Feb 2021 at 19:11, Benjamin Fair  
> > > wrote:
> > >>
> > >> On Thu, 18 Feb 2021 at 04:42,  wrote:
> > >> >
> > >> > From: "Anton D. Kachalov" 
> > >> >
> > >> > This change satisfy OpenBMC requirements for flash layout.
> > >> >
> > >> > Signed-off-by: Anton D. Kachalov 
> > >> > ---
> > >> >  arch/arm/boot/dts/nuvoton-npcm750-evb.dts | 28
> > >> > +++
> > >> >  1 file changed, 8 insertions(+), 20 deletions(-)
> > >> >
> > >> > diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> > >> > b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> > >> > index bd1eb6ee380f..741c1fee8552 100644
> > >> > --- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> > >> > +++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
> > >> > @@ -182,8 +182,8 @@ bbuboot2@8 {
> > >> > reg = <0x008 0x8>;
> &g

Re: [PATCH] ntfs: check for valid standard information attribute

2021-02-22 Thread Anton Altaparmakov
Hi Andrew,

Sorry for the delay in replying.

> On 19 Feb 2021, at 18:49, Andrew Morton  wrote:
> 
> On Fri, 19 Feb 2021 01:54:30 +0000 Anton Altaparmakov  
> wrote:
> 
>> Hi Andrew,
>> 
>> Can you please push this one upstream?  Thanks a lot in advance!
> 
> The changelog is a bit brief...

Yes you are right it is a bit brief.  I guess I thought the syzkaller link was 
sufficient...  Rustam would you like to resubmit with an improved/extended 
description?

>>> On 17 Feb 2021, at 15:59, Rustam Kovhaev  wrote:
>>> 
>>> we should check for valid STANDARD_INFORMATION attribute offset and
>>> length before trying to access it
> 
> It's a kernel a crash and I assume it results from mounting a corrupted
> filesystem?
> 
> I think it's worth a cc:stable, yes?

The problem is an invalid memory access due to corrupt on-disk metadata.

The issue with NTFS is that it is effectively a relational database so it is 
full of "struct X, field A" contains offset to "struct Y" so you get: " 
Y =  X + X->A" and if the value of A is corrupt on-disk then your Y 
pointer is now pointing to random memory.

The patch fixes one such place by validating that Y pointer is within bounds of 
the structure/buffer it is in.

So I guess this could be worth a cc:stable?  I guess we can add it and Greg / 
others can decide whether to put it into stable or not...  Rustam when 
resubmitting with better description, please also add the "Cc: 
sta...@vger.kernel.org" line together with the "Signed-off-by", etc lines (note 
no need to actually put this in CC: field of the email iteslf).

Best regards,

Anton
-- 
Anton Altaparmakov  (replace at with @)
Lead in File System Development, Tuxera Inc., http://www.tuxera.com/
Linux NTFS maintainer



Re: [PATCH] ARM: dts: nuvoton: Fix flash layout

2021-02-22 Thread Anton Kachalov
Hi, Tom.

Yes, I'm using it for testing on real hardware.

BTW. Recent u-boot doesn't work with SD cards. The card doesn't
detect. The last working version was this one:

https://github.com/Nuvoton-Israel/nuvoton-info/tree/master/npcm7xx-poleg/evaluation-board/sw_deliverables/npcm7xx_v2.3

However, u-boot from igps repo:

https://github.com/Nuvoton-Israel/igps/tree/master/ImageGeneration/versions

Has issues too. It doesn't allow me to read more than 4k bytes once at
a time. Thus, to flash the stuff I have manually read chunks from the
SD-card: fat load doesn't work at all and I write that data in raw
partition.

On Sun, 21 Feb 2021 at 17:40, Tomer Maimon  wrote:
>
> Hi Benjamin and Anton,
>
> Sorry for the late reply,
>
> The EVB FIU0-CS0 partitioning is used for testing the EVB and this is why it 
> is different than the OpenBMC flash layout.
>
>
>
> Are you using the NPCM7XX EVB for OpenBMC? if yes we can consider to modify 
> the flash partition to OpenBMC use.
>
>
> On Thu, 18 Feb 2021 at 19:11, Benjamin Fair  wrote:
>>
>> On Thu, 18 Feb 2021 at 04:42,  wrote:
>> >
>> > From: "Anton D. Kachalov" 
>> >
>> > This change satisfy OpenBMC requirements for flash layout.
>> >
>> > Signed-off-by: Anton D. Kachalov 
>> > ---
>> >  arch/arm/boot/dts/nuvoton-npcm750-evb.dts | 28 +++
>> >  1 file changed, 8 insertions(+), 20 deletions(-)
>> >
>> > diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts 
>> > b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
>> > index bd1eb6ee380f..741c1fee8552 100644
>> > --- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
>> > +++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
>> > @@ -182,8 +182,8 @@ bbuboot2@8 {
>> > reg = <0x008 0x8>;
>> > read-only;
>> > };
>> > -   envparam@10 {
>> > -   label = "env-param";
>> > +   ubootenv@10 {
>> > +   label = "u-boot-env";
>> > reg = <0x010 0x4>;
>> > read-only;
>> > };
>> > @@ -195,25 +195,13 @@ kernel@20 {
>> > label = "kernel";
>> > reg = <0x020 0x40>;
>> > };
>> > -   rootfs@60 {
>> > -   label = "rootfs";
>> > -   reg = <0x060 0x70>;
>> > +   rofs@78 {
>> > +   label = "rofs";
>> > +   reg = <0x078 0x168>;
>> > };
>> > -   spare1@D0 {
>> > -   label = "spare1";
>> > -   reg = <0x0D0 0x20>;
>> > -   };
>> > -   spare2@0F0 {
>> > -   label = "spare2";
>> > -   reg = <0x0F0 0x20>;
>> > -   };
>> > -   spare3@110 {
>> > -   label = "spare3";
>> > -   reg = <0x110 0x20>;
>> > -   };
>> > -   spare4@130 {
>> > -   label = "spare4";
>> > -   reg = <0x130 0x0>;
>> > +   rwfs@1e0 {
>> > +   label = "rwfs";
>> > +   reg = <0x1e0 0x20>;
>> > };
>>
>> I recommend just including the openbmc-flash-layout.dtsi file here
>> instead since that contains the common flash layout for most OpenBMC
>> systems.
>>
> Good solution,
> Do you mean nuvoton-openbmc-flash-layout?
>>
>> > };
>> > };
>> > --
>> > 2.30.0.478.g8a0d178c01-goog
>> >
>
>
> Thanks,
>
> Tomer


Re: NFS Caching broken in 4.19.37

2021-02-21 Thread Anton Ivanov

On 21/02/2021 14:37, Bruce Fields wrote:

On Sun, Feb 21, 2021 at 11:38:51AM +, Anton Ivanov wrote:

On 21/02/2021 09:13, Salvatore Bonaccorso wrote:

On Sat, Feb 20, 2021 at 08:16:26PM +, Chuck Lever wrote:

Confirming you are varying client-side kernels. Should the Linux
NFS client maintainers be Cc'd?

Ok, agreed. Let's add them as well. NFS client maintainers any ideas
on how to trackle this?

This is not observed with Debian backports 5.10 package

uname -a
Linux madding 5.10.0-0.bpo.3-amd64 #1 SMP Debian 5.10.13-1~bpo10+1
(2021-02-11) x86_64 GNU/Linux

I'm still unclear: when you say you tested a certain kernel: are you
varying the client-side kernel version, or the server side, or both at
once?


Client side. This seems to be an entirely client side issue.

A variety of kernels on the clients starting from 4.9 and up to 5.10 
using 4.19 servers. I have observed it on a 4.9 client versus 4.9 server 
earlier.


4.9 fails, 4.19 fails, 5.2 fails, 5.4 fails, 5.10 works.

At present the server is at 4.19.67 in all tests.

Linux jain 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) 
x86_64 GNU/Linux


I can set-up a couple of alternative servers during the week, but so far 
everything is pointing towards a client fs cache issue, not a server one.


Brgds,


--b.



--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/



[PATCH v4 8/9] ALSA: virtio: introduce PCM channel map support

2021-02-21 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 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 4578d0ce0726..787a4dec1da8 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -222,6 +222,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)
@@ -234,6 +238,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 9e6cd79eda25..8ec8bc3ea75e 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -44,6 +44,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;
@@ -57,6 +59,8 @@ struct virtio_snd {
unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
+   struct virtio_snd_chmap_info *chmaps;
+   unsigned int nchmaps;
 };
 
 /* Message completion timeout in milliseconds (module parameter). */
@@ -102,4 +106,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 ..c54d7daa13e3
--- /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 
+
+#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
+};
+
+/**
+ * v

[PATCH v4 7/9] ALSA: virtio: introduce jack support

2021-02-21 Thread Anton Yakovlev
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 
---
 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 a845978111d6..4578d0ce0726 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -67,6 +67,10 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
virtqueue_disable_cb(vqueue);
while ((event = virtqueue_get_buf(vqueue, ))) {
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);
@@ -210,10 +214,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 aca87059564e..9e6cd79eda25 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;
 
 /**
@@ -39,6 +40,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.
  */
@@ -50,6 +53,8 @@ struct virtio_snd {
struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
struct list_head pcm_list;
+   struct virtio_jack *jacks;
+   unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
 };
@@ -90,4 +95,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 ..a78cf465171d
--- /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 
+#include 
+#include 
+
+#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;
+   unsigned int nid;
+   unsigned int features;
+   unsigned int defconf;
+   unsigned int caps;
+   bool connected;
+   int type;
+};
+
+/**
+ * virtsnd_jack_get_label() - Get the name string for the jack.

[PATCH v4 6/9] ALSA: virtio: PCM substream operators

2021-02-21 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_pcm.c |   2 +
 sound/virtio/virtio_pcm.h |   4 +
 sound/virtio/virtio_pcm_ops.c | 469 ++
 4 files changed, 477 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 c88258f6a521..5f7b4090c6a2 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -455,6 +455,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, _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 d6be62b52421..4378918b441a 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -35,6 +35,7 @@ struct virtio_pcm_msg;
  * @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.
+ * @msg_flushing: True if the I/O queue is in flushing state.
  */
 struct virtio_pcm_substream {
struct virtio_snd *snd;
@@ -56,6 +57,7 @@ struct virtio_pcm_substream {
int msg_last_enqueued;
unsigned int msg_count;
wait_queue_head_t msg_empty;
+   bool msg_flushing;
 };
 
 /**
@@ -82,6 +84,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 ..07510778b555
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+
+#include "virtio_card.h"
+
+/* 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 },
+   { 4

[PATCH v4 9/9] ALSA: virtio: introduce device suspend/resume support

2021-02-21 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/virtio_card.c| 57 +++
 sound/virtio/virtio_pcm.c |  1 +
 sound/virtio/virtio_pcm_ops.c | 44 ---
 3 files changed, 91 insertions(+), 11 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 787a4dec1da8..1f0a0fa7bbc0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -373,6 +373,59 @@ static void virtsnd_config_changed(struct virtio_device 
*vdev)
 "sound device configuration was changed\n");
 }
 
+#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;
+
+   /* Stop all the virtqueues. */
+   vdev->config->reset(vdev);
+   vdev->config->del_vqs(vdev);
+
+   virtsnd_ctl_msg_cancel_all(snd);
+
+   kfree(snd->event_msgs);
+
+   /*
+* If the virtsnd_restore() fails before re-allocating events, then we
+* get a dangling pointer here.
+*/
+   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 },
@@ -386,6 +439,10 @@ static struct virtio_driver virtsnd_driver = {
.probe = virtsnd_probe,
.remove = virtsnd_remove,
.config_changed = virtsnd_config_changed,
+#ifdef CONFIG_PM_SLEEP
+   .freeze = virtsnd_freeze,
+   .restore = virtsnd_restore,
+#endif
 };
 
 static int __init init(void)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 5f7b4090c6a2..d7471e0a9d04 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index 07510778b555..ccef64502c13 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -218,6 +218,10 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream 
*substream,
if (rc)
return rc;
 
+   /* If messages have already been allocated before, do nothing. */
+   if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
+   return 0;
+
return virtsnd_pcm_msg_alloc(vss, periods, period_bytes);
 }
 
@@ -258,19 +262,21 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream 
*substream)
}
 
spin_lock_irqsave(>lock, flags);
-   /*
-* Since I/O messages are asynchronous, they can be completed
-* when the runtime structure no longer exists. Since each
-* completion implies incrementing the hw_ptr, we cache all the
-* current values needed to compute the new hw_ptr value.
-*/
-   vss->frame_bytes = runtime->frame_bits >> 3;
-   vss->period_size = runtime->period_size;
-   vss->buffer_size = runtime->buffer_size;
+   if (runtime->status->state != SNDRV_PCM_STATE_SUSPENDED) {
+   /*
+* Since I/O messages are asynchronous, they can be completed
+* when the runtime structure no longer exists. Since each
+* completion implies incrementing the hw_ptr, we cache all the
+* current values needed to compute the new hw_ptr value.
+*/
+   vss->frame_bytes = runtime->frame_bits >> 3;
+   vss->period_size = runtime->period_size;
+   vss->buffer_size = runtime->buffer_size;
 
-   vss->hw_ptr = 0;
+   vss->hw_ptr = 0;
+   vss->msg_last_enqueued = -1;
+   }
vss->xfer_xrun = false;
-   vss->msg_last_enqueued = -1;
vss->msg_count = 0;
spin_unlock_irqrestore(>lock, flags);
 
@@ -300,6 +306

[PATCH v4 2/9] ALSA: virtio: add virtio sound driver

2021-02-21 Thread Anton Yakovlev
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. Also, handling DEVICE_NEEDS_RESET device
status.

Signed-off-by: Anton Yakovlev 
---
 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  | 340 
 sound/virtio/virtio_card.h  |  67 +++
 8 files changed, 771 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 bfc1b86e3e73..599c1231214d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18945,6 +18945,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..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 
+
+/***
+ * 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) */
+  

[PATCH v4 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-02-21 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  18 +-
 sound/virtio/virtio_card.h|   9 +
 sound/virtio/virtio_pcm.c |  32 +++
 sound/virtio/virtio_pcm.h |  42 
 sound/virtio/virtio_pcm_msg.c | 392 ++
 6 files changed, 493 insertions(+), 3 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 235afc25fce7..a845978111d6 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -65,8 +65,16 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
spin_lock_irqsave(>lock, flags);
do {
virtqueue_disable_cb(vqueue);
-   while ((event = virtqueue_get_buf(vqueue, )))
+   while ((event = virtqueue_get_buf(vqueue, ))) {
+   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;
+   }
+
virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
+   }
if (unlikely(virtqueue_is_broken(vqueue)))
break;
} while (!virtqueue_enable_cb(vqueue));
@@ -87,7 +95,9 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
struct virtio_device *vdev = snd->vdev;
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
};
const char *names[VIRTIO_SND_VQ_MAX] = {
[VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
@@ -299,6 +309,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;
 
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
@@ -310,6 +321,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
 
vdev->config->del_vqs(vdev);
 
+   for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
+   virtsnd_pcm_msg_free(>substreams[i]);
+
kfree(snd->event_msgs);
 }
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 687d3ed6d1c3..aca87059564e 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -81,4 +81,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
return >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 9c2cf9eaa0c7..c88258f6a521 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -338,6 +338,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
 
vss->snd = snd;
vss->sid = i;
+   init_waitqueue_head(>msg_empty);
+   spin_lock_init(>lock);
 
rc = virtsnd_pcm_build_hw(vss, [i]);
if (rc)
@@ -462,3 +464,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_sn

[PATCH v4 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-02-21 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   3 +-
 sound/virtio/virtio_card.c |  14 ++
 sound/virtio/virtio_card.h |  10 +
 sound/virtio/virtio_pcm.c  | 464 +
 sound/virtio/virtio_pcm.h  |  71 ++
 5 files changed, 561 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 c62b3a2da148..235afc25fce7 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -200,6 +200,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);
 }
 
@@ -228,6 +238,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (virtsnd_pcm_validate(vdev))
+   return -EINVAL;
+
return 0;
 }
 
@@ -251,6 +264,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
INIT_LIST_HEAD(>ctl_msgs);
+   INIT_LIST_HEAD(>pcm_list);
 
vdev->priv = snd;
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index c51a71a79388..687d3ed6d1c3 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -12,9 +12,13 @@
 #include 
 
 #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.
@@ -34,6 +38,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;
@@ -42,6 +49,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;
+   unsigned int 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 ..9c2cf9eaa0c7
--- /dev/null
+++ b/sound/virtio/virtio_pcm.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+#include 
+
+#include "virtio_card.h"
+
+static unsigned int pcm_buffer_ms = 160;
+module_param(pcm_buffer_ms, uint, 0644);
+MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds");
+
+static unsigned int pcm_periods_min = 2;
+module_param(pcm_periods_min, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods");
+
+static unsigned int pcm_periods_max = 16;
+module_param(pcm_periods_max, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods");
+
+static unsigned int 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 unsigned int 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_

[PATCH v4 3/9] ALSA: virtio: handling control messages

2021-02-21 Thread Anton Yakovlev
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 
---
 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 b5f63b5b7db4..c62b3a2da148 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -11,6 +11,10 @@
 
 #include "virtio_card.h"
 
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
 static void virtsnd_remove(struct virtio_device *vdev);
 
 /**
@@ -82,6 +86,7 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
 {
struct virtio_device *vdev = snd->vdev;
vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
+   [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
};
const char *names[VIRTIO_SND_VQ_MAX] = {
@@ -218,6 +223,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (!msg_timeout_ms) {
+   dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+   return -EINVAL;
+   }
+
return 0;
 }
 
@@ -240,6 +250,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
 
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
+   INIT_LIST_HEAD(>ctl_msgs);
 
vdev->priv = snd;
 
@@ -278,6 +289,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
 
+   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 244381cc7a9b..c51a71a79388 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -11,6 +11,8 @@
 #include 
 #include 
 
+#include "virtio_ctl_msg.h"
+
 #define VIRTIO_SND_CARD_DRIVER "virtio-snd"
 #define VIRTIO_SND_CARD_NAME   "VirtIO SoundCard"
 
@@ -30,6 +32,7 @@ struct virtio_snd_queue {
  * @queues: Virtqueue wrappers.
  * @reset_work: Reset device work.
  * @card: ALSA sound card.
+ * @ctl_msgs: Pending control request list.
  * @event_msgs: Device events.
  */
 struct virtio_snd {
@@ -37,9 +40,13 @@ struct virtio_snd {
struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
struct work_struct reset_work;
struct snd_card *card;
+   struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
 };
 
+/* Message completion timeout in milliseconds (module parameter). */
+extern int 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 ..67a5a0301ba3
--- /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 
+#include 
+
+#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(>ref_count);
+}
+
+/**
+ * virtsnd_ctl_msg_unref() - Decrement reference c

[PATCH v4 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-02-21 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.0




Re: NFS Caching broken in 4.19.37

2021-02-21 Thread Anton Ivanov

On 21/02/2021 09:13, Salvatore Bonaccorso wrote:

Hi,

On Sat, Feb 20, 2021 at 08:16:26PM +, Chuck Lever wrote:




On Feb 20, 2021, at 3:13 PM, Anton Ivanov  
wrote:

On 20/02/2021 20:04, Salvatore Bonaccorso wrote:

Hi,

On Mon, Jul 08, 2019 at 07:19:54PM +0100, Anton Ivanov wrote:

Hi list,

NFS caching appears broken in 4.19.37.

The more cores/threads the easier to reproduce. Tested with identical
results on Ryzen 1600 and 1600X.

1. Mount an openwrt build tree over NFS v4
2. Run make -j `cat /proc/cpuinfo | grep vendor | wc -l` ; make clean in a
loop
3. Result after 3-4 iterations:

State on the client

ls -laF 
/var/autofs/local/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm

total 8
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../

State as seen on the server (mounted via nfs from localhost):

ls -laF 
/var/autofs/local/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm
total 12
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../
-rw-r--r-- 1 anivanov anivanov   32 Jul  8 11:40 ipcbuf.h

Actual state on the filesystem:

ls -laF 
/exports/work/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm
total 12
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../
-rw-r--r-- 1 anivanov anivanov   32 Jul  8 11:40 ipcbuf.h

So the client has quite clearly lost the plot. Telling it to drop caches and
re-reading the directory shows the file present.

It is possible to reproduce this using a linux kernel tree too, just takes
much more iterations - 10+ at least.

Both client and server run 4.19.37 from Debian buster. This is filed as
debian bug 931500. I originally thought it to be autofs related, but IMHO it
is actually something fundamentally broken in nfs caching resulting in cache
corruption.

According to the reporter downstream in Debian, at
https://bugs.debian.org/940821#26 thi seem still reproducible with
more recent kernels than the initial reported. Is there anything Anton
can provide to try to track down the issue?

Anton, can you reproduce with current stable series?


100% reproducible with any kernel from 4.9 to 5.4, stable or backports. It may 
exist in earlier versions, but I do not have a machine with anything before 4.9 
to test at present.


Confirming you are varying client-side kernels. Should the Linux
NFS client maintainers be Cc'd?


Ok, agreed. Let's add them as well. NFS client maintainers any ideas
on how to trackle this?


This is not observed with Debian backports 5.10 package

uname -a
Linux madding 5.10.0-0.bpo.3-amd64 #1 SMP Debian 5.10.13-1~bpo10+1 
(2021-02-11) x86_64 GNU/Linux


I left the testcase running for ~ 4 hours on a 6core/12thread Ryzen. It 
should have blown up 10 times by now.


So one of the commits between 5.4 and 5.10.13 fixed it.

If nobody can think of a particular commit which fixes it, I can try 
dissecting it during the week.


A.






 From 1-2 make clean && make  cycles to one afternoon depending on the number 
of machine cores. More cores/threads the faster it does it.

I tried playing with protocol minor versions, caching options, etc - it is 
still reproducible for any nfs4 settings as long as there is client side 
caching of metadata.

A.



Regards,
Salvatore



--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/


--
Chuck Lever


Regards,
Salvatore




--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/


Re: NFS Caching broken in 4.19.37

2021-02-20 Thread Anton Ivanov

On 20/02/2021 20:04, Salvatore Bonaccorso wrote:

Hi,

On Mon, Jul 08, 2019 at 07:19:54PM +0100, Anton Ivanov wrote:

Hi list,

NFS caching appears broken in 4.19.37.

The more cores/threads the easier to reproduce. Tested with identical
results on Ryzen 1600 and 1600X.

1. Mount an openwrt build tree over NFS v4
2. Run make -j `cat /proc/cpuinfo | grep vendor | wc -l` ; make clean in a
loop
3. Result after 3-4 iterations:

State on the client

ls -laF 
/var/autofs/local/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm

total 8
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../

State as seen on the server (mounted via nfs from localhost):

ls -laF 
/var/autofs/local/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm
total 12
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../
-rw-r--r-- 1 anivanov anivanov   32 Jul  8 11:40 ipcbuf.h

Actual state on the filesystem:

ls -laF 
/exports/work/src/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_tiny/linux-4.14.125/arch/mips/include/generated/uapi/asm
total 12
drwxr-xr-x 2 anivanov anivanov 4096 Jul  8 11:40 ./
drwxr-xr-x 3 anivanov anivanov 4096 Jul  8 11:40 ../
-rw-r--r-- 1 anivanov anivanov   32 Jul  8 11:40 ipcbuf.h

So the client has quite clearly lost the plot. Telling it to drop caches and
re-reading the directory shows the file present.

It is possible to reproduce this using a linux kernel tree too, just takes
much more iterations - 10+ at least.

Both client and server run 4.19.37 from Debian buster. This is filed as
debian bug 931500. I originally thought it to be autofs related, but IMHO it
is actually something fundamentally broken in nfs caching resulting in cache
corruption.

According to the reporter downstream in Debian, at
https://bugs.debian.org/940821#26 thi seem still reproducible with
more recent kernels than the initial reported. Is there anything Anton
can provide to try to track down the issue?

Anton, can you reproduce with current stable series?


100% reproducible with any kernel from 4.9 to 5.4, stable or backports. 
It may exist in earlier versions, but I do not have a machine with 
anything before 4.9 to test at present.


From 1-2 make clean && make  cycles to one afternoon depending on the 
number of machine cores. More cores/threads the faster it does it.


I tried playing with protocol minor versions, caching options, etc - it 
is still reproducible for any nfs4 settings as long as there is client 
side caching of metadata.


A.



Regards,
Salvatore



--
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/



Re: [PATCH] ntfs: check for valid standard information attribute

2021-02-18 Thread Anton Altaparmakov
Hi Andrew,

Can you please push this one upstream?  Thanks a lot in advance!

Best regards,

Anton

> On 17 Feb 2021, at 15:59, Rustam Kovhaev  wrote:
> 
> we should check for valid STANDARD_INFORMATION attribute offset and
> length before trying to access it
> 
> Reported-and-tested-by: syzbot+c584225dabdea2f71...@syzkaller.appspotmail.com
> Signed-off-by: Rustam Kovhaev 
> Acked-by: Anton Altaparmakov 
> Link: https://syzkaller.appspot.com/bug?extid=c584225dabdea2f71969
> ---
> fs/ntfs/inode.c | 6 ++
> 1 file changed, 6 insertions(+)
> 
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index f7e4cbc26eaf..be4ff9386ec0 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -629,6 +629,12 @@ static int ntfs_read_locked_inode(struct inode *vi)
>   }
>   a = ctx->attr;
>   /* Get the standard information attribute value. */
> + if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
> + + le32_to_cpu(a->data.resident.value_length) >
> + (u8 *)ctx->mrec + vol->mft_record_size) {
> + ntfs_error(vi->i_sb, "Corrupt standard information attribute in 
> inode.");
> + goto unm_err_out;
> + }
>   si = (STANDARD_INFORMATION*)((u8*)a +
>   le16_to_cpu(a->data.resident.value_offset));
> 
> -- 
> 2.30.0
> 


-- 
Anton Altaparmakov  (replace at with @)
Lead in File System Development, Tuxera Inc., http://www.tuxera.com/
Linux NTFS maintainer



Re: [PATCH] ntfs: move check for valid resident attribute offset and length

2021-02-15 Thread Anton Altaparmakov
Hi Rustam,

Thank you for the patch but it is not quite correct:

1) The first delta: yes that is a good idea to add this check but the error 
message is incorrect.  It should say "Corrupt standard information attribute in 
inode." instead.

2) The second delta: The check of the attribute list attribute needs to remain, 
i.e. your second delta needs to be deleted.

Please could you address both of the above comments and then resend?  Please 
then also add: "Acked-by: Anton Altaparmakov " to the patch.

Thanks a lot in advance!

Best regards,

Anton

> On 14 Feb 2021, at 22:12, Rustam Kovhaev  wrote:
> 
> we should check for valid resident atribute offset and length before
> loading STANDARD_INFORMATION attribute in ntfs_read_locked_inode()
> let's make that check a bit earlier in the same function to avoid
> use-after-free bug
> 
> Reported-and-tested-by: syzbot+c584225dabdea2f71...@syzkaller.appspotmail.com
> Signed-off-by: Rustam Kovhaev 
> Link: https://syzkaller.appspot.com/bug?extid=c584225dabdea2f71969
> ---
> fs/ntfs/inode.c | 15 +++
> 1 file changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index f7e4cbc26eaf..70745aea5106 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -629,6 +629,13 @@ static int ntfs_read_locked_inode(struct inode *vi)
>   }
>   a = ctx->attr;
>   /* Get the standard information attribute value. */
> + if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
> + + le32_to_cpu(
> + a->data.resident.value_length) >
> + (u8 *)ctx->mrec + vol->mft_record_size) {
> + ntfs_error(vi->i_sb, "Corrupt attribute list in inode.");
> + goto unm_err_out;
> + }
>   si = (STANDARD_INFORMATION*)((u8*)a +
>   le16_to_cpu(a->data.resident.value_offset));
> 
> @@ -731,14 +738,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
>   goto unm_err_out;
>   }
>   } else /* if (!a->non_resident) */ {
> - if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
> - + le32_to_cpu(
> - a->data.resident.value_length) >
> - (u8*)ctx->mrec + vol->mft_record_size) {
> - ntfs_error(vi->i_sb, "Corrupt attribute list "
> - "in inode.");
> - goto unm_err_out;
> -     }
>   /* Now copy the attribute list. */
>   memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
>   a->data.resident.value_offset),
> -- 
> 2.30.0
> 


-- 
Anton Altaparmakov  (replace at with @)
Lead in File System Development, Tuxera Inc., http://www.tuxera.com/
Linux NTFS maintainer



[PATCH v3 8/9] ALSA: virtio: introduce PCM channel map support

2021-02-09 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 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 4578d0ce0726..787a4dec1da8 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -222,6 +222,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)
@@ -234,6 +238,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 9e6cd79eda25..8ec8bc3ea75e 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -44,6 +44,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;
@@ -57,6 +59,8 @@ struct virtio_snd {
unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
+   struct virtio_snd_chmap_info *chmaps;
+   unsigned int nchmaps;
 };
 
 /* Message completion timeout in milliseconds (module parameter). */
@@ -102,4 +106,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 ..c54d7daa13e3
--- /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 
+
+#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
+};
+
+/**
+ * v

[PATCH v3 9/9] ALSA: virtio: introduce device suspend/resume support

2021-02-09 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/virtio_card.c| 57 +++
 sound/virtio/virtio_pcm.c |  1 +
 sound/virtio/virtio_pcm_ops.c | 44 ---
 3 files changed, 91 insertions(+), 11 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index 787a4dec1da8..1f0a0fa7bbc0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -373,6 +373,59 @@ static void virtsnd_config_changed(struct virtio_device 
*vdev)
 "sound device configuration was changed\n");
 }
 
+#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;
+
+   /* Stop all the virtqueues. */
+   vdev->config->reset(vdev);
+   vdev->config->del_vqs(vdev);
+
+   virtsnd_ctl_msg_cancel_all(snd);
+
+   kfree(snd->event_msgs);
+
+   /*
+* If the virtsnd_restore() fails before re-allocating events, then we
+* get a dangling pointer here.
+*/
+   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 },
@@ -386,6 +439,10 @@ static struct virtio_driver virtsnd_driver = {
.probe = virtsnd_probe,
.remove = virtsnd_remove,
.config_changed = virtsnd_config_changed,
+#ifdef CONFIG_PM_SLEEP
+   .freeze = virtsnd_freeze,
+   .restore = virtsnd_restore,
+#endif
 };
 
 static int __init init(void)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 1d98de878385..401d4c975d2b 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -109,6 +109,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*vss,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index c2224f5461c4..207f4877a5ec 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -220,6 +220,10 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream 
*substream,
if (rc)
return rc;
 
+   /* If messages have already been allocated before, do nothing. */
+   if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
+   return 0;
+
return virtsnd_pcm_msg_alloc(vss, periods, period_bytes);
 }
 
@@ -260,19 +264,21 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream 
*substream)
}
 
spin_lock_irqsave(>lock, flags);
-   /*
-* Since I/O messages are asynchronous, they can be completed
-* when the runtime structure no longer exists. Since each
-* completion implies incrementing the hw_ptr, we cache all the
-* current values needed to compute the new hw_ptr value.
-*/
-   vss->frame_bytes = runtime->frame_bits >> 3;
-   vss->period_size = runtime->period_size;
-   vss->buffer_size = runtime->buffer_size;
+   if (runtime->status->state != SNDRV_PCM_STATE_SUSPENDED) {
+   /*
+* Since I/O messages are asynchronous, they can be completed
+* when the runtime structure no longer exists. Since each
+* completion implies incrementing the hw_ptr, we cache all the
+* current values needed to compute the new hw_ptr value.
+*/
+   vss->frame_bytes = runtime->frame_bits >> 3;
+   vss->period_size = runtime->period_size;
+   vss->buffer_size = runtime->buffer_size;
 
-   vss->hw_ptr = 0;
+   vss->hw_ptr = 0;
+   vss->msg_last_enqueued = -1;
+   }
vss->xfer_xrun = false;
-   vss->msg_last_enqueued = -1;
vss->msg_count = 0;
spin_unlock_irqrestore(>lock, flags);
 
@@ -302,6 +308

[PATCH v3 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-02-09 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   3 +-
 sound/virtio/virtio_card.c |  14 ++
 sound/virtio/virtio_card.h |  10 +
 sound/virtio/virtio_pcm.c  | 464 +
 sound/virtio/virtio_pcm.h  |  71 ++
 5 files changed, 561 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 c62b3a2da148..235afc25fce7 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -200,6 +200,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);
 }
 
@@ -228,6 +238,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (virtsnd_pcm_validate(vdev))
+   return -EINVAL;
+
return 0;
 }
 
@@ -251,6 +264,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
INIT_LIST_HEAD(>ctl_msgs);
+   INIT_LIST_HEAD(>pcm_list);
 
vdev->priv = snd;
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index c51a71a79388..687d3ed6d1c3 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -12,9 +12,13 @@
 #include 
 
 #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.
@@ -34,6 +38,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;
@@ -42,6 +49,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;
+   unsigned int 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 ..92f2f4cb338f
--- /dev/null
+++ b/sound/virtio/virtio_pcm.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+#include 
+
+#include "virtio_card.h"
+
+static unsigned int pcm_buffer_ms = 160;
+module_param(pcm_buffer_ms, uint, 0644);
+MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds");
+
+static unsigned int pcm_periods_min = 2;
+module_param(pcm_periods_min, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods");
+
+static unsigned int pcm_periods_max = 16;
+module_param(pcm_periods_max, uint, 0644);
+MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods");
+
+static unsigned int 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 unsigned int 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 unsigned int g_v2a_format_map[] = {
+   [VIRTIO_SND_PCM_FMT_IMA_ADPCM] = SNDRV_

[PATCH v3 6/9] ALSA: virtio: PCM substream operators

2021-02-09 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_pcm.c |   2 +
 sound/virtio/virtio_pcm.h |   4 +
 sound/virtio/virtio_pcm_ops.c | 471 ++
 4 files changed, 479 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 a74fbfb9f35c..1d98de878385 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -455,6 +455,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, _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 d6be62b52421..4378918b441a 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -35,6 +35,7 @@ struct virtio_pcm_msg;
  * @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.
+ * @msg_flushing: True if the I/O queue is in flushing state.
  */
 struct virtio_pcm_substream {
struct virtio_snd *snd;
@@ -56,6 +57,7 @@ struct virtio_pcm_substream {
int msg_last_enqueued;
unsigned int msg_count;
wait_queue_head_t msg_empty;
+   bool msg_flushing;
 };
 
 /**
@@ -82,6 +84,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 ..c2224f5461c4
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+
+#include "virtio_card.h"
+
+/* Map for converting ALSA format to VirtIO format. */
+struct virtsnd_a2v_format {
+   unsigned int 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 },
+   { 4

[PATCH v3 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-02-09 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  18 +-
 sound/virtio/virtio_card.h|   9 +
 sound/virtio/virtio_pcm.c |  32 +++
 sound/virtio/virtio_pcm.h |  42 
 sound/virtio/virtio_pcm_msg.c | 393 ++
 6 files changed, 494 insertions(+), 3 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 235afc25fce7..a845978111d6 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -65,8 +65,16 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
spin_lock_irqsave(>lock, flags);
do {
virtqueue_disable_cb(vqueue);
-   while ((event = virtqueue_get_buf(vqueue, )))
+   while ((event = virtqueue_get_buf(vqueue, ))) {
+   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;
+   }
+
virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
+   }
if (unlikely(virtqueue_is_broken(vqueue)))
break;
} while (!virtqueue_enable_cb(vqueue));
@@ -87,7 +95,9 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
struct virtio_device *vdev = snd->vdev;
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
};
const char *names[VIRTIO_SND_VQ_MAX] = {
[VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
@@ -299,6 +309,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;
 
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
@@ -310,6 +321,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
 
vdev->config->del_vqs(vdev);
 
+   for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
+   virtsnd_pcm_msg_free(>substreams[i]);
+
kfree(snd->event_msgs);
 }
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 687d3ed6d1c3..aca87059564e 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -81,4 +81,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
return >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 92f2f4cb338f..a74fbfb9f35c 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -338,6 +338,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
 
vss->snd = snd;
vss->sid = i;
+   init_waitqueue_head(>msg_empty);
+   spin_lock_init(>lock);
 
rc = virtsnd_pcm_build_hw(vss, [i]);
if (rc)
@@ -462,3 +464,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_sn

[PATCH v3 7/9] ALSA: virtio: introduce jack support

2021-02-09 Thread Anton Yakovlev
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 
---
 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 a845978111d6..4578d0ce0726 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -67,6 +67,10 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
virtqueue_disable_cb(vqueue);
while ((event = virtqueue_get_buf(vqueue, ))) {
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);
@@ -210,10 +214,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 aca87059564e..9e6cd79eda25 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;
 
 /**
@@ -39,6 +40,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.
  */
@@ -50,6 +53,8 @@ struct virtio_snd {
struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
struct list_head pcm_list;
+   struct virtio_jack *jacks;
+   unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
 };
@@ -90,4 +95,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 ..a78cf465171d
--- /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 
+#include 
+#include 
+
+#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;
+   unsigned int nid;
+   unsigned int features;
+   unsigned int defconf;
+   unsigned int caps;
+   bool connected;
+   int type;
+};
+
+/**
+ * virtsnd_jack_get_label() - Get the name string for the jack.

[PATCH v3 3/9] ALSA: virtio: handling control messages

2021-02-09 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  13 ++
 sound/virtio/virtio_card.h|   7 +
 sound/virtio/virtio_ctl_msg.c | 311 ++
 sound/virtio/virtio_ctl_msg.h |  78 +
 5 files changed, 411 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 b5f63b5b7db4..c62b3a2da148 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -11,6 +11,10 @@
 
 #include "virtio_card.h"
 
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
 static void virtsnd_remove(struct virtio_device *vdev);
 
 /**
@@ -82,6 +86,7 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
 {
struct virtio_device *vdev = snd->vdev;
vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
+   [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
};
const char *names[VIRTIO_SND_VQ_MAX] = {
@@ -218,6 +223,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (!msg_timeout_ms) {
+   dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+   return -EINVAL;
+   }
+
return 0;
 }
 
@@ -240,6 +250,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
 
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
+   INIT_LIST_HEAD(>ctl_msgs);
 
vdev->priv = snd;
 
@@ -278,6 +289,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
 
+   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 244381cc7a9b..c51a71a79388 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -11,6 +11,8 @@
 #include 
 #include 
 
+#include "virtio_ctl_msg.h"
+
 #define VIRTIO_SND_CARD_DRIVER "virtio-snd"
 #define VIRTIO_SND_CARD_NAME   "VirtIO SoundCard"
 
@@ -30,6 +32,7 @@ struct virtio_snd_queue {
  * @queues: Virtqueue wrappers.
  * @reset_work: Reset device work.
  * @card: ALSA sound card.
+ * @ctl_msgs: Pending control request list.
  * @event_msgs: Device events.
  */
 struct virtio_snd {
@@ -37,9 +40,13 @@ struct virtio_snd {
struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
struct work_struct reset_work;
struct snd_card *card;
+   struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
 };
 
+/* Message completion timeout in milliseconds (module parameter). */
+extern int 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 ..4b60b99c1d27
--- /dev/null
+++ b/sound/virtio/virtio_ctl_msg.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio-snd: Virtio sound device
+ * Copyright (C) 2021 OpenSynergy GmbH
+ */
+#include 
+#include 
+
+#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(>ref_count);
+}
+
+/**
+ * virtsnd_ctl_msg_unref() - Decrement reference c

[PATCH v3 2/9] ALSA: virtio: add virtio sound driver

2021-02-09 Thread Anton Yakovlev
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. Also, handling DEVICE_NEEDS_RESET device
status.

Signed-off-by: Anton Yakovlev 
---
 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  | 340 
 sound/virtio/virtio_card.h  |  67 +++
 8 files changed, 771 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 2a0737dfca89..51f20656a5ad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18945,6 +18945,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..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 
+
+/***
+ * 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) */
+  

[PATCH v3 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-02-09 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.0




Re: [virtio-dev] Re: [PATCH v2 2/9] ALSA: virtio: add virtio sound driver

2021-02-03 Thread Anton Yakovlev

Hi Takashi,


On 03.02.2021 17:59, Takashi Iwai wrote:

On Tue, 02 Feb 2021 00:18:09 +0100,
Anton Yakovlev wrote:

+/**
+ * virtsnd_reset_fn() - Kernel worker's function to reset the device.
+ * @work: Reset device work.
+ *
+ * Context: Process context.
+ */
+static void virtsnd_reset_fn(struct work_struct *work)
+{
+ struct virtio_snd *snd =
+ container_of(work, struct virtio_snd, reset_work);
+ struct virtio_device *vdev = snd->vdev;
+ struct device *dev = >dev;
+ int rc;
+
+ dev_info(dev, "sound device needs reset\n");
+
+ /*
+  * It seems that the only way to properly reset the device is to
remove
+  * and re-create the ALSA sound card device.
+  *
+  * Also resetting the device involves a number of steps with
setting the
+  * status bits described in the virtio specification. And the
easiest
+  * way to get everything right is to use the virtio bus interface.
+  */
+ rc = dev->bus->remove(dev);
+ if (rc)
+ dev_warn(dev, "bus->remove() failed: %d", rc);
+
+ rc = dev->bus->probe(dev);
+ if (rc)
+ dev_err(dev, "bus->probe() failed: %d", rc);


This looks very suspicious to me. Wondering what ALSA maintainers

will say

to this.


I'm also wondering what the virtio people have to say. This part is a
purely virtio specific thing. And since none of the existing virtio
drivers processes the request to reset the device, it is not clear what
is the best way to proceed here. For this reason, the most
straightforward and simple solution was chosen.


What is this "reset" actually supposed to do?  Reconfguring
everything, or changing only certain parameters, devices, whatever?


It means bringing this particular device to its initial state.

After that, the driver can re-read the configurations from the device
and reconfigure everything.



thanks,

Takashi



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin



Re: [PATCH v2 8/9] ALSA: virtio: introduce PCM channel map support

2021-02-01 Thread Anton Yakovlev




On 26.01.2021 10:22, Guennadi Liakhovetski wrote:
> CAUTION: This email originated from outside of the organization.
> Do not click links or open attachments unless you recognize the sender
> and know the content is safe.
>
>
> On Sun, 24 Jan 2021, Anton Yakovlev wrote:
>
>> Enumerate all available PCM channel maps and create ALSA controls.
>>
>> Signed-off-by: Anton Yakovlev 
>> ---
>> sound/virtio/Makefile   |   1 +
>> sound/virtio/virtio_card.c  |  15 +++
>> sound/virtio/virtio_card.h  |   8 ++
>> sound/virtio/virtio_chmap.c | 237 
>> sound/virtio/virtio_pcm.h   |   4 +
>> 5 files changed, 265 insertions(+)
>> create mode 100644 sound/virtio/virtio_chmap.c
>
> [snip]
>
>> diff --git a/sound/virtio/virtio_chmap.c b/sound/virtio/virtio_chmap.c
>> new file mode 100644
>> index ..8a2ddc4dcffb
>> --- /dev/null
>> +++ b/sound/virtio/virtio_chmap.c
>> @@ -0,0 +1,237 @@
>
> [snip]
>
>> +/**
>> + * 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;
>> + unsigned int i;
>> + int rc;
>> +
>> + virtio_cread(vdev, struct virtio_snd_config, chmaps,
>> >nchmaps);
>> + if (!snd->nchmaps)
>> + return 0;
>> +
>> + snd->chmaps = devm_kcalloc(>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 = >chmaps[i];
>> + unsigned int nid = le32_to_cpu(info->hdr.hda_fn_nid);
>> + struct virtio_pcm *pcm;
>> + struct virtio_pcm_stream *stream;
>> +
>> + pcm = virtsnd_pcm_find_or_create(snd, nid);
>> + if (IS_ERR(pcm))
>> + return PTR_ERR(pcm);
>> +
>> + switch (info->direction) {
>> + case VIRTIO_SND_D_OUTPUT: {
>> + stream = >streams[SNDRV_PCM_STREAM_PLAYBACK];
>> + break;
>> + }
>> + case VIRTIO_SND_D_INPUT: {
>> + stream = >streams[SNDRV_PCM_STREAM_CAPTURE];
>> + break;
>> + }
>> + default: {
>> + dev_err(>dev,
>> + "chmap #%u: unknown direction (%u)\n", i,
>> + info->direction);
>> + return -EINVAL;
>> + }
>> + }
>> +
>> + stream->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).
>> + * @stream: 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 *stream)
>> +{
>> + unsigned int i;
>> + int max_channels = 0;
>> +
>> + for (i = 0; i < stream->nchmaps; i++)
>> + if (max_channels < stream->chmaps[i].channels)
>> + max_channels = stream->chmaps[i].channels;
>> +
>> + return snd_pcm_add_chmap_ctls(pcm, direction, stream->chmaps,
>> +   max_channels, 0, NULL);
>> +}
>> +
>> +/**
>> + * virtsnd_chmap_build_devs() - Build ALSA controls for channel maps.
>> + * @snd: VirtIO sound device.
>> + *
>> + * Context: Any 

Re: [PATCH v2 6/9] ALSA: virtio: PCM substream operators

2021-02-01 Thread Anton Yakovlev




On 25.01.2021 17:59, Guennadi Liakhovetski wrote:
> On Sun, 24 Jan 2021, Anton Yakovlev wrote:
>
> [snip]
>
>> +/**
>> + * virtsnd_pcm_release() - Release the PCM substream on the device 
side.

>> + * @substream: VirtIO substream.
>> + *
>> + * Context: Any context that permits to sleep.
>> + * Return: 0 on success, -errno on failure.
>> + */
>> +static inline bool virtsnd_pcm_released(struct virtio_pcm_substream
>> *substream)
>> +{
>> + /*
>> +  * 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.
>> +  */
>> + return atomic_read(>msg_count) == 0;
>
> Also here having it atomic doesn't really seem to help. This just means,
> that at some point of time it was == 0.

Technically, you're right. In practice, everything looks like this:

I/O messages are added to the virtqueue either at the start of the
substream or in the interrupt handler (and only as long as .xfer_enabled
is true). In general, this means that the .msg_count can only be
incremented in the interrupt handler. As soon as the substream stops,
the .xfer_enabled becomes false and the .msg_count no longer increases.
This means that the .msg_count was either already 0, or we need to wait
for it to become 0.


>> +}
>> +
>> +static int virtsnd_pcm_release(struct virtio_pcm_substream *substream)
>
> kernel-doc missing

Yeap, thanks!


>> +{
>> + struct virtio_snd *snd = substream->snd;
>> + struct virtio_snd_msg *msg;
>> + unsigned int js = msecs_to_jiffies(msg_timeout_ms);
>> + int rc;
>> +
>> + msg = virtsnd_pcm_ctl_msg_alloc(substream,
>> VIRTIO_SND_R_PCM_RELEASE,
>> + GFP_KERNEL);
>> + if (IS_ERR(msg))
>> + return PTR_ERR(msg);
>> +
>> + rc = virtsnd_ctl_msg_send_sync(snd, msg);
>> + if (rc)
>> + return rc;
>> +
>> + return wait_event_interruptible_timeout(substream->msg_empty,
>> +
>> virtsnd_pcm_released(substream),
>> + js);
>
> wait_event_interruptible_timeout() will return a positive number in
> success cases, 0 means a timeout and condition still false. Whereas when
> you call this function you interpret 0 as success and you expect any != 0
> to be a negative error. Wondering how this worked during your tests?

Yeah, that's actually a bug. We haven't hit a timeout on that control path.


>> +}
>> +
>> +/**
>> + * virtsnd_pcm_open() - Open the PCM substream.
>> + * @substream: Kernel ALSA substream.
>> + *
>> + * Context: Any context.
>> + * Return: 0 on success, -errno on failure.
>> + */
>> +static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
>> +{
>> + struct virtio_pcm *pcm = snd_pcm_substream_chip(substream);
>> + struct virtio_pcm_substream *ss = NULL;
>> +
>> + if (pcm) {
>> + switch (substream->stream) {
>> + case SNDRV_PCM_STREAM_PLAYBACK:
>> + case SNDRV_PCM_STREAM_CAPTURE: {
>> + struct virtio_pcm_stream *stream =
>> + >streams[substream->stream];
>> +
>> + if (substream->number < stream->nsubstreams)
>
> Can this condition ever be false?

Hard to tell. But there may be some bug. In general, I try to adhere to
the rule that if an array element is referenced by index, it is better
to check the index value first.


>> + ss = 
stream->substreams[substream->number];

>> + break;
>> + }
>> + }
>> + }
>> +
>> + if (!ss)
>> + return -EBADFD;
>> +
>> + substream->runtime->hw = ss->hw;
>> + substream->private_data = ss;
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * virtsnd_pcm_close() - Close the PCM substream.
>> + * @substream: Kernel ALSA substream.
>> + *
>> + * Context: Any context.
>> + * Return: 0.
>> + */
>> +static int virtsnd_pcm_close(struct snd_pcm_substream *substream)
>> +{
>> + return 0;
>> +}
>> +
>> +/**
>> + * virtsnd_pcm_hw_params() - Set the parameters of the PCM substream.
>> + * @substream: Kernel ALSA substream.
>

Re: [PATCH v2 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-02-01 Thread Anton Yakovlev
t; +
>> +/**
>> + * virtsnd_pcm_msg_complete() - Complete an I/O message.
>> + * @msg: I/O message.
>> + * @size: Number of bytes written.
>> + *
>> + * Completion of the message means the elapsed period.
>> + *
>> + * The interrupt handler modifies three fields of the substream
>> structure
>> + * (hw_ptr, xfer_xrun, msg_count) that are used in operator
>> functions. These
>> + * values are atomic to avoid frequent interlocks with the interrupt
>> handler.
>> + * This becomes especially important in the case of multiple running
>> substreams
>> + * that share both the virtqueue and interrupt handler.
>> + *
>> + * Context: Interrupt context.
>> + */
>> +static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg,
>> size_t size)
>> +{
>> + struct virtio_pcm_substream *substream = msg->substream;
>> + snd_pcm_uframes_t hw_ptr;
>> + unsigned int msg_count;
>> +
>> + /*
>> +  * 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.
>> +  */
>> + hw_ptr = (snd_pcm_uframes_t)atomic_read(>hw_ptr);
>
> Also unclear why this has to be atomic, especially taking into account
> that it's only accessed in "interrupt context."

The general situation looks like this:
.hw_ptr and .xfer_xrun
  written in the virtsnd_pcm_msg_complete()
  read in the pointer() substream operator
.xfer_enabled
  written in the trigger() substream operator
  read in the virtsnd_pcm_msg_complete()

ALSA takes some substream locks while calling for trigger/pointer().
Unfortunately, we cannot use the same substream locks here, as it opens
up many control paths leading to deadlock. And all that remains is either
to use atomic fields, or to introduce our own spinlock for each substream
(to protect these fields). Personally, I don't know which would be better.
But the code with atomic fields looks at least simpler.


>> +
>> + /*
>> +  * If the capture substream returned an incorrect status, then 
just

>> +  * increase the hw_ptr by the period size.
>> +  */
>> + if (substream->direction == SNDRV_PCM_STREAM_PLAYBACK ||
>> + size <= sizeof(msg->status)) {
>> + hw_ptr += substream->period_size;
>> + } else {
>> + size -= sizeof(msg->status);
>> + hw_ptr += size / substream->frame_bytes;
>> + }
>> +
>> + atomic_set(>hw_ptr, (u32)(hw_ptr %
>> substream->buffer_size));
>> + atomic_set(>xfer_xrun, 0);
>> +
>> + msg_count = atomic_dec_return(>msg_count);
>> +
>> + if (atomic_read(>xfer_enabled)) {
>> + struct snd_pcm_runtime *runtime =
>> substream->substream->runtime;
>> +
>> + runtime->delay =
>> + bytes_to_frames(runtime,
>> +
>> le32_to_cpu(msg->status.latency_bytes));
>> +
>> + snd_pcm_period_elapsed(substream->substream);
>> +
>> + virtsnd_pcm_msg_send(substream);
>> + } else if (!msg_count) {
>> + wake_up_all(>msg_empty);
>> + }
>> +}
>
> Thanks
> Guennadi
>
--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin

www.opensynergy.com



Re: [virtio-dev] Re: [PATCH v2 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-02-01 Thread Anton Yakovlev




On 25.01.2021 16:44, Guennadi Liakhovetski wrote:
> On Sun, 24 Jan 2021, Anton Yakovlev wrote:
>

...[snip]...

>>
>> diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
>> index 955eadc2d858..39fe13b43dd1 100644
>> --- a/sound/virtio/virtio_card.c
>> +++ b/sound/virtio/virtio_card.c
>> @@ -92,6 +92,17 @@ static void virtsnd_event_notify_cb(struct
>> virtqueue *vqueue)
>>   if (!event)
>>   break;
>>
>> + switch (le32_to_cpu(event->hdr.code)) {
>> + case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
>> + case VIRTIO_SND_EVT_PCM_XRUN: {
>
> In the previous patch you had a switch-case statement complying to the
> common kernel coding style. It isn't specified in coding-style.rst, but
> these superfluous braces really don't seem to be good for anything - in
> this and multiple other switch-case statements in the series.

I will fix this. Thanks!


...[snip]...


>> @@ -359,6 +384,8 @@ static int virtsnd_probe(struct virtio_device *vdev)
>> static void virtsnd_remove(struct virtio_device *vdev)
>> {
>>   struct virtio_snd *snd = vdev->priv;
>> + struct virtio_pcm *pcm;
>> + struct virtio_pcm *pcm_next;
>>
>>   if (!snd)
>>   return;
>> @@ -376,6 +403,24 @@ static void virtsnd_remove(struct virtio_device
>> *vdev)
>>   vdev->config->reset(vdev);
>>   vdev->config->del_vqs(vdev);
>>
>> + list_for_each_entry_safe(pcm, pcm_next, >pcm_list, list) {
>> + unsigned int i;
>> +
>> + list_del(>list);
>> +
>> + for (i = 0; i < ARRAY_SIZE(pcm->streams); ++i) {
>> + struct virtio_pcm_stream *stream =
>> >streams[i];
>> +
>> + if (stream->substreams)
>> + devm_kfree(>dev, 
stream->substreams);

>> + }
>> +
>> + devm_kfree(>dev, pcm);
>
> Please double-check both devm_kfree() calls above. Probably they aren't
> needed in the .remove() method.

Then I will redo these parts, and the parts that you noticed in the rest
of the comments to this file.


...[snip]...


>
> Thanks
> Guennadi
>
> -
> To unsubscribe, e-mail: virtio-dev-unsubscr...@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-h...@lists.oasis-open.org
>
>
--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin

www.opensynergy.com



Re: [virtio-dev] Re: [PATCH v2 3/9] ALSA: virtio: handling control messages

2021-02-01 Thread Anton Yakovlev
tter as there is no harm in propagating
the error returned by virtqueue_add_sgs.


>> +}
>> +
>> +/**
>> + * virtsnd_ctl_msg_send_sync() - Send a (synchronous) control 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. Takes and releases the control queue spinlock.
>> + * 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.
>> + */
>> +int virtsnd_ctl_msg_send_sync(struct virtio_snd *snd,
>> +   struct virtio_snd_msg *msg)
>> +{
>> + struct virtio_device *vdev = snd->vdev;
>> + unsigned int js = msecs_to_jiffies(msg_timeout_ms);
>> + struct virtio_snd_hdr *response;
>> + int rc;
>> +
>> + virtsnd_ctl_msg_ref(vdev, msg);
>> +
>> + rc = virtsnd_ctl_msg_send(snd, msg);
>> + if (rc)
>> + goto on_failure;
>> +
>> + rc = wait_for_completion_interruptible_timeout(>notify, js);
>> + if (rc <= 0) {
>> + if (!rc) {
>> + struct virtio_snd_hdr *request =
>> + sg_virt(>sg_request);
>> +
>> + dev_err(>dev,
>> + "control message (0x%08x) timeout\n",
>> + le32_to_cpu(request->code));
>> + rc = -EIO;
>
> Wouldn't -ETIMEDOUT be better here?

Yes, it would be.


>> + }
>> +
>> + goto on_failure;
>> + }
>> +
>> + response = sg_virt(>sg_response);
>> +
>> + switch (le32_to_cpu(response->code)) {
>> + case VIRTIO_SND_S_OK:
>> + rc = 0;
>> + break;
>> + case VIRTIO_SND_S_BAD_MSG:
>> + rc = -EINVAL;
>> + break;
>> + case VIRTIO_SND_S_NOT_SUPP:
>> + rc = -EOPNOTSUPP;
>> + break;
>> + case VIRTIO_SND_S_IO_ERR:
>> + rc = -EIO;
>> + break;
>> + default:
>> + rc = -EPERM;
>
> any special reason for EPERM as a default error code? I think often 
EINVAL

> is used in similar cases.

No, there is no particular reason, I just wasn't sure what to choose for
the default value.


>> + break;
>> + }
>> +
>> +on_failure:
>
> cosmetic: this path is also taken on success, so maybe better just call
> the lable "exit" or similar.

Ok! Then I probably need to check for other goto cases as well.


...[snip]...


>> +
>> +/**
>> + * virtsnd_ctl_msg_unref() - Decrement reference counter for the
>> message.
>> + * @vdev: VirtIO parent device.
>> + * @msg: Control message.
>> + *
>> + * The message will be freed when the ref_count value is 0.
>> + *
>> + * Context: Any context.
>> + */
>> +static inline void virtsnd_ctl_msg_unref(struct virtio_device *vdev,
>> +  struct virtio_snd_msg *msg)
>> +{
>> + if (!atomic_dec_return(>ref_count))
>
> Since you use atomic operations, this function can probably be called 
with

> no additional locking right? But if so, couldn't it be preempted here
> between the check and the call to kfree()? As was mentioned in a previous
> review, the use of atomic operations in this series has to be very
> carefully examined...

The control message workflow is implemented in such a way that all
necessary increments occur before the first possible call to this
function. So even if preemption does occur, it shouldn't be a problem.


>> + devm_kfree(>dev, msg);
>> +}
>> +


...[snip]...


>
> -
> To unsubscribe, e-mail: virtio-dev-unsubscr...@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-h...@lists.oasis-open.org
>
>
--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin

www.opensynergy.com



Re: [virtio-dev] Re: [PATCH v2 2/9] ALSA: virtio: add virtio sound driver

2021-02-01 Thread Anton Yakovlev
 dev_warn(dev, "bus->remove() failed: %d", rc);
>> +
>> + rc = dev->bus->probe(dev);
>> + if (rc)
>> + dev_err(dev, "bus->probe() failed: %d", rc);
>
> This looks very suspicious to me. Wondering what ALSA maintainers 
will say

> to this.

I'm also wondering what the virtio people have to say. This part is a
purely virtio specific thing. And since none of the existing virtio
drivers processes the request to reset the device, it is not clear what
is the best way to proceed here. For this reason, the most
straightforward and simple solution was chosen.


...[snip]...

>
> Thanks
> Guennadi
>
> -
> To unsubscribe, e-mail: virtio-dev-unsubscr...@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-h...@lists.oasis-open.org
>
>
--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin

www.opensynergy.com



[PATCH v2 9/9] ALSA: virtio: introduce device suspend/resume support

2021-01-24 Thread Anton Yakovlev
All running PCM substreams are stopped on device suspend and restarted
on device resume.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/virtio_card.c| 54 
 sound/virtio/virtio_pcm.c | 40 +++
 sound/virtio/virtio_pcm.h |  6 +++
 sound/virtio/virtio_pcm_ops.c | 93 ---
 4 files changed, 154 insertions(+), 39 deletions(-)

diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
index fabf91fc1c9c..90dadf18d9b0 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -491,6 +491,56 @@ static void virtsnd_config_changed(struct virtio_device 
*vdev)
 "sound device configuration was changed\n");
 }
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * virtsnd_freeze() - Suspend device.
+ * @vdev: VirtIO parent device.
+ *
+ * Context: Any context that permits to sleep.
+ * Return: 0 on success, -errno on failure.
+ */
+static int virtsnd_freeze(struct virtio_device *vdev)
+{
+   struct virtio_snd *snd = vdev->priv;
+
+   virtsnd_disable_vqs(snd);
+
+   vdev->config->reset(vdev);
+   vdev->config->del_vqs(vdev);
+
+   return 0;
+}
+
+/**
+ * virtsnd_restore() - Resume device.
+ * @vdev: VirtIO parent device.
+ *
+ * Context: Any context that permits to sleep.
+ * 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);
+
+   if (snd->nsubstreams) {
+   rc = virtsnd_pcm_restore(snd);
+   if (rc)
+   return rc;
+   }
+
+   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 },
@@ -504,6 +554,10 @@ static struct virtio_driver virtsnd_driver = {
.probe = virtsnd_probe,
.remove = virtsnd_remove,
.config_changed = virtsnd_config_changed,
+#ifdef CONFIG_PM_SLEEP
+   .freeze = virtsnd_freeze,
+   .restore = virtsnd_restore,
+#endif
 };
 
 static int __init init(void)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 6a1ca6b2c3ca..68d9c6dee13a 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -122,6 +122,7 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*substream,
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
@@ -511,6 +512,45 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd)
return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * virtsnd_pcm_restore() - Resume PCM substreams.
+ * @snd: VirtIO sound device.
+ *
+ * Context: Any context that permits to sleep.
+ * Return: 0 on success, -errno on failure.
+ */
+int virtsnd_pcm_restore(struct virtio_snd *snd)
+{
+   unsigned int i;
+
+   for (i = 0; i < snd->nsubstreams; ++i) {
+   struct virtio_pcm_substream *substream = >substreams[i];
+   struct snd_pcm_substream *ksubstream = substream->substream;
+   int rc;
+
+   if (!substream->suspended)
+   continue;
+
+   /*
+* We restart the substream by executing the standard command
+* sequence. The START command will be sent from a subsequent
+* call to the trigger() callback function after the device has
+* been resumed.
+*/
+   rc = ksubstream->ops->hw_params(ksubstream, NULL);
+   if (rc)
+   return rc;
+
+   rc = ksubstream->ops->prepare(ksubstream);
+   if (rc)
+   return rc;
+   }
+
+   return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
 /**
  * virtsnd_pcm_event() - Handle the PCM device event notification.
  * @snd: VirtIO sound device.
diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
index a326b921b947..23d0fdd57225 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -41,6 +41,7 @@ struct virtio_pcm_msg;
  * @hw_ptr: Substream hardware pointer value in frames [0 ... buffer_size).
  * @xfer_enabled: Data transfer state (0 - off, 1 - on).
  * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
+ * @suspended: Kernel ALSA substream is suspended.
  * @msgs: 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.
@@ -60,6 +61,7 @@ struct virtio_

[PATCH v2 8/9] ALSA: virtio: introduce PCM channel map support

2021-01-24 Thread Anton Yakovlev
Enumerate all available PCM channel maps and create ALSA controls.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile   |   1 +
 sound/virtio/virtio_card.c  |  15 +++
 sound/virtio/virtio_card.h  |   8 ++
 sound/virtio/virtio_chmap.c | 237 
 sound/virtio/virtio_pcm.h   |   4 +
 5 files changed, 265 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 1dd709437208..fabf91fc1c9c 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -308,6 +308,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)
@@ -320,6 +324,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);
 }
 
@@ -438,6 +448,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
 
if (stream->substreams)
devm_kfree(>dev, stream->substreams);
+   if (stream->chmaps)
+   devm_kfree(>dev, stream->chmaps);
}
 
devm_kfree(>dev, pcm);
@@ -449,6 +461,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
if (snd->substreams)
devm_kfree(>dev, snd->substreams);
 
+   if (snd->chmaps)
+   devm_kfree(>dev, snd->chmaps);
+
devm_kfree(>dev, snd);
 
vdev->priv = NULL;
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index df4b0696e8c4..09c6e9ab80ca 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -52,6 +52,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;
@@ -65,6 +67,8 @@ struct virtio_snd {
unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
+   struct virtio_snd_chmap_info *chmaps;
+   unsigned int nchmaps;
 };
 
 /* Message completion timeout in milliseconds (module parameter). */
@@ -110,4 +114,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 ..8a2ddc4dcffb
--- /dev/null
+++ b/sound/virtio/virtio_chmap.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include 
+
+#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,
+  

[PATCH v2 6/9] ALSA: virtio: PCM substream operators

2021-01-24 Thread Anton Yakovlev
Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_pcm.c |   5 +-
 sound/virtio/virtio_pcm.h |   2 +
 sound/virtio/virtio_pcm_ops.c | 513 ++
 4 files changed, 521 insertions(+), 2 deletions(-)
 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 1ab50dcc88c8..6a1ca6b2c3ca 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -121,7 +121,8 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*substream,
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
-   SNDRV_PCM_INFO_INTERLEAVED;
+   SNDRV_PCM_INFO_INTERLEAVED |
+   SNDRV_PCM_INFO_PAUSE;
 
if (!info->channels_min || info->channels_min > info->channels_max) {
dev_err(>dev,
@@ -503,6 +504,8 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd)
if (rc)
return rc;
}
+
+   snd_pcm_set_ops(pcm->pcm, i, _pcm_ops);
}
 
return 0;
diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
index d011b7e1d18d..fe467bc05d8b 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -90,6 +90,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 ..19882777fcd6
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include 
+
+#include "virtio_card.h"
+
+/*
+ * Our main concern here is maintaining the correct state of the underlying I/O
+ * virtqueues. Thus, operators are implemented to support all of the following
+ * possible control paths (excluding all trivial ones):
+ *
+ *+-+
+ *| open()  |<--+
+ *+++   |
+ * v|
+ *  +--+--+ |
+ *   +->| hw_params() |<-+  |
+ *   |  +-+  |  |
+ *   | v |  |
+ *   |   +---+   |  |
+ *   |   | prepare() |<---+  |  |
+ *   |   +---+|  |  |
+ *   | v  |  |  |
+ *   |+-+ |  |  |
+ * +---+  | trigger(START/  | |  |  |
+ * | restore() |  | PAUSE_RELEASE/  |<-+  |  |  |
+ * +---+  | RESUME) |  |  |  |  |
+ *   ^+-+  |  |  |  |
+ *   | v   |  |  |  |
+ *   |   +---+ |  |  |  |
+ *   |   | pointer() | |  |  |  |
+ *   |   +---+ |  |  |  |
+ *   | v   |  |  |  |
+ *   |  +-+|  |  |  |
+ * +---+| trigger(STOP/   |+  |  |  |
+ * | freeze()  |<---| PAUSE_PUSH/ |---+  |  |
+ * +---+| SUSPEND)|  |  |
+ *  +--

[PATCH v2 7/9] ALSA: virtio: introduce jack support

2021-01-24 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   1 +
 sound/virtio/virtio_card.c |  18 +++
 sound/virtio/virtio_card.h |  12 ++
 sound/virtio/virtio_jack.c | 255 +
 4 files changed, 286 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 11d025ee77c2..1dd709437208 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -93,6 +93,11 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
break;
 
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);
@@ -295,10 +300,20 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
strscpy(snd->card->longname, "VirtIO Sound Card",
sizeof(snd->card->longname));
 
+   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)
@@ -428,6 +443,9 @@ static void virtsnd_remove(struct virtio_device *vdev)
devm_kfree(>dev, pcm);
}
 
+   if (snd->jacks)
+   devm_kfree(>dev, snd->jacks);
+
if (snd->substreams)
devm_kfree(>dev, snd->substreams);
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index b11c09984882..df4b0696e8c4 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -26,6 +26,7 @@
 #include "virtio_ctl_msg.h"
 #include "virtio_pcm.h"
 
+struct virtio_jack;
 struct virtio_pcm_substream;
 
 /**
@@ -47,6 +48,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.
  */
@@ -58,6 +61,8 @@ struct virtio_snd {
struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
struct list_head pcm_list;
+   struct virtio_jack *jacks;
+   unsigned int njacks;
struct virtio_pcm_substream *substreams;
unsigned int nsubstreams;
 };
@@ -98,4 +103,11 @@ virtsnd_pcm_queue(struct virtio_pcm_substream *substream)
return virtsnd_rx_queue(substream->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 ..83593c59f6bf
--- /dev/null
+++ b/sound/virtio/virtio_jack.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include 
+#include 
+#include 
+
+#include "virtio_card.h"
+
+/**
+ * 

[PATCH v2 5/9] ALSA: virtio: handling control and I/O messages for the PCM device

2021-01-24 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  10 ++
 sound/virtio/virtio_card.h|   9 +
 sound/virtio/virtio_pcm.c |   3 +
 sound/virtio/virtio_pcm.h |  31 
 sound/virtio/virtio_pcm_msg.c | 325 ++
 6 files changed, 380 insertions(+), 1 deletion(-)
 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 39fe13b43dd1..11d025ee77c2 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -143,6 +143,12 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
callbacks[VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb;
callbacks[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb;
 
+   virtio_cread(vdev, struct virtio_snd_config, streams, );
+   if (n) {
+   callbacks[VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb;
+   callbacks[VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb;
+   }
+
rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
 NULL);
if (rc) {
@@ -177,6 +183,10 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
  * virtsnd_enable_event_vq() - Enable the event virtqueue.
  * @snd: VirtIO sound device.
  *
+ * The tx queue is enabled only if the device supports playback stream(s).
+ *
+ * The rx queue is enabled only if the device supports capture stream(s).
+ *
  * Context: Any context.
  */
 static void virtsnd_enable_event_vq(struct virtio_snd *snd)
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index be6651a6aaf8..b11c09984882 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -89,4 +89,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
return >queues[VIRTIO_SND_VQ_RX];
 }
 
+static inline struct virtio_snd_queue *
+virtsnd_pcm_queue(struct virtio_pcm_substream *substream)
+{
+   if (substream->direction == SNDRV_PCM_STREAM_PLAYBACK)
+   return virtsnd_tx_queue(substream->snd);
+   else
+   return virtsnd_rx_queue(substream->snd);
+}
+
 #endif /* VIRTIO_SND_CARD_H */
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index 036990b7b78a..1ab50dcc88c8 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -376,6 +376,7 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd)
 
substream->snd = snd;
substream->sid = i;
+   init_waitqueue_head(>msg_empty);
 
rc = virtsnd_pcm_build_hw(substream, [i]);
if (rc)
@@ -530,6 +531,8 @@ void virtsnd_pcm_event(struct virtio_snd *snd, struct 
virtio_snd_event *event)
break;
}
case VIRTIO_SND_EVT_PCM_XRUN: {
+   if (atomic_read(>xfer_enabled))
+   atomic_set(>xfer_xrun, 1);
break;
}
}
diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
index 73fb4d9dc524..d011b7e1d18d 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -24,6 +24,7 @@
 #include 
 
 struct virtio_pcm;
+struct virtio_pcm_msg;
 
 /**
  * struct virtio_pcm_substream - VirtIO PCM substream.
@@ -34,6 +35,16 @@ struct virtio_pcm;
  * @features: Stream VirtIO feature bit map (1 << VIRTIO_SND_PCM_F_XXX).
  * @substream: Kernel ALSA substream.
  * @hw: Kernel ALSA substream hardware descriptor.
+ * @frame_bytes: Current frame size in bytes.
+ * @period_size: Current period size in frames.
+ * @buffer_size: Current buffer size in frames.
+ * @hw_ptr: Substream hardware pointer value in frames [0 ... buffer_size).
+ * @xfer_enabled: Data transfer state (0 - off, 1 - on).
+ * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun).
+ * @msgs: 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.

[PATCH v2 4/9] ALSA: virtio: build PCM devices and substream hardware descriptors

2021-01-24 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile  |   3 +-
 sound/virtio/virtio_card.c |  45 
 sound/virtio/virtio_card.h |   9 +
 sound/virtio/virtio_pcm.c  | 536 +
 sound/virtio/virtio_pcm.h  |  89 ++
 5 files changed, 681 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 955eadc2d858..39fe13b43dd1 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -92,6 +92,17 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
if (!event)
break;
 
+   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;
+   }
+   default: {
+   break;
+   }
+   }
+
virtsnd_event_send(queue->vqueue, event, true,
   GFP_ATOMIC);
}
@@ -274,6 +285,16 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
strscpy(snd->card->longname, "VirtIO Sound Card",
sizeof(snd->card->longname));
 
+   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);
 }
 
@@ -302,6 +323,9 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (virtsnd_pcm_validate(vdev))
+   return -EINVAL;
+
return 0;
 }
 
@@ -325,6 +349,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
INIT_LIST_HEAD(>ctl_msgs);
+   INIT_LIST_HEAD(>pcm_list);
 
vdev->priv = snd;
 
@@ -359,6 +384,8 @@ static int virtsnd_probe(struct virtio_device *vdev)
 static void virtsnd_remove(struct virtio_device *vdev)
 {
struct virtio_snd *snd = vdev->priv;
+   struct virtio_pcm *pcm;
+   struct virtio_pcm *pcm_next;
 
if (!snd)
return;
@@ -376,6 +403,24 @@ static void virtsnd_remove(struct virtio_device *vdev)
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
 
+   list_for_each_entry_safe(pcm, pcm_next, >pcm_list, list) {
+   unsigned int i;
+
+   list_del(>list);
+
+   for (i = 0; i < ARRAY_SIZE(pcm->streams); ++i) {
+   struct virtio_pcm_stream *stream = >streams[i];
+
+   if (stream->substreams)
+   devm_kfree(>dev, stream->substreams);
+   }
+
+   devm_kfree(>dev, pcm);
+   }
+
+   if (snd->substreams)
+   devm_kfree(>dev, snd->substreams);
+
devm_kfree(>dev, snd);
 
vdev->priv = NULL;
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 37b734a92134..be6651a6aaf8 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -24,6 +24,9 @@
 #include 
 
 #include "virtio_ctl_msg.h"
+#include "virtio_pcm.h"
+
+struct virtio_pcm_substream;
 
 /**
  * struct virtio_snd_queue - Virtqueue wrapper structure.
@@ -43,6 +46,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;
@@ -51,6 +57,9 @@ struct virtio_snd {
struct snd_card *card;
struct list_head

[PATCH v2 1/9] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-01-24 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.0




Re: [PATCH 0/7] ALSA: add virtio sound driver

2021-01-24 Thread Anton Yakovlev

Hi, Liam!


On 20.01.2021 11:10, Girdwood, Liam R wrote:

CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know 
the content is safe.


Hi Anton,

On Wed, 2021-01-20 at 01:36 +0100, Anton Yakovlev wrote:

This series implements a driver part of the virtio sound device
specification v8 [1].

The driver supports PCM playback and capture substreams, jack and
channel map controls. A message-based transport is used to write/read
PCM frames to/from a device.

The series is based (and was actually tested) on Linus's master
branch [2], on top of

commit 1e2a199f6ccd ("Merge tag 'spi-fix-v5.11-rc4' of ...")

As a device part was used OpenSynergy proprietary implementation.

Any comments are very welcome.



This just looks like the guest front end here, do you have a follow up
series for the host backend ?


As I mentioned in the cover message, as a device part was used our own
proprietary implementation. And there are no plans to upstream that
part.



Thanks

Liam
-
Intel Corporation (UK) Limited
Registered No. 1134945 (England)
Registered Office: Pipers Way, Swindon SN3 1RJ
VAT No: 860 2173 47

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.



--
Anton Yakovlev
Senior Software Engineer

OpenSynergy GmbH
Rotherstr. 20, 10245 Berlin

Phone: +49 30 60 98 54 0
E-Mail: anton.yakov...@opensynergy.com

www.opensynergy.com

Handelsregister/Commercial Registry: Amtsgericht Charlottenburg, HRB 108616B
Geschäftsführer/Managing Director: Regis Adjamah



[PATCH v2 3/9] ALSA: virtio: handling control messages

2021-01-24 Thread Anton Yakovlev
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 
---
 sound/virtio/Makefile |   3 +-
 sound/virtio/virtio_card.c|  20 +++
 sound/virtio/virtio_card.h|   7 +
 sound/virtio/virtio_ctl_msg.c | 293 ++
 sound/virtio/virtio_ctl_msg.h | 122 ++
 5 files changed, 444 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 532d823fdf6f..955eadc2d858 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -24,6 +24,10 @@
 
 #include "virtio_card.h"
 
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
 static void virtsnd_remove(struct virtio_device *vdev);
 
 /**
@@ -125,6 +129,7 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
unsigned int n = 0;
int rc;
 
+   callbacks[VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb;
callbacks[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb;
 
rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
@@ -193,6 +198,15 @@ static void virtsnd_disable_vqs(struct virtio_snd *snd)
if (queue->vqueue)
virtqueue_disable_cb(queue->vqueue);
queue->vqueue = NULL;
+   /* Cancel all pending requests for the control queue */
+   if (i == VIRTIO_SND_VQ_CONTROL) {
+   struct virtio_snd_msg *msg;
+   struct virtio_snd_msg *next;
+
+   list_for_each_entry_safe(msg, next, >ctl_msgs,
+list)
+   virtsnd_ctl_msg_complete(snd, msg);
+   }
spin_unlock_irqrestore(>lock, flags);
}
 
@@ -283,6 +297,11 @@ static int virtsnd_validate(struct virtio_device *vdev)
return -EINVAL;
}
 
+   if (!msg_timeout_ms) {
+   dev_err(>dev, "msg_timeout_ms value cannot be zero\n");
+   return -EINVAL;
+   }
+
return 0;
 }
 
@@ -305,6 +324,7 @@ static int virtsnd_probe(struct virtio_device *vdev)
 
snd->vdev = vdev;
INIT_WORK(>reset_work, virtsnd_reset_fn);
+   INIT_LIST_HEAD(>ctl_msgs);
 
vdev->priv = snd;
 
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index 10084abaaf18..37b734a92134 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -23,6 +23,8 @@
 #include 
 #include 
 
+#include "virtio_ctl_msg.h"
+
 /**
  * struct virtio_snd_queue - Virtqueue wrapper structure.
  * @lock: Used to synchronize access to a virtqueue.
@@ -39,6 +41,7 @@ struct virtio_snd_queue {
  * @queues: Virtqueue wrappers.
  * @reset_work: Reset device work.
  * @card: ALSA sound card.
+ * @ctl_msgs: Pending control request list.
  * @event_msgs: Device events.
  */
 struct virtio_snd {
@@ -46,9 +49,13 @@ struct virtio_snd {
struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX];
struct work_struct reset_work;
struct snd_card *card;
+   struct list_head ctl_msgs;
struct virtio_snd_event *event_msgs;
 };
 
+/* Message completion timeout in milliseconds (module parameter). */
+extern int 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 ..c1701756bc32
--- /dev/null
+++ b/sound/virtio/virtio_ctl_msg.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for mo

[PATCH v2 2/9] ALSA: virtio: add virtio sound driver

2021-01-24 Thread Anton Yakovlev
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. Also, handling DEVICE_NEEDS_RESET device
status.

Signed-off-by: Anton Yakovlev 
---
 MAINTAINERS |   9 +
 include/uapi/linux/virtio_snd.h | 361 +++
 sound/Kconfig   |   2 +
 sound/Makefile  |   3 +-
 sound/virtio/Kconfig|  10 +
 sound/virtio/Makefile   |   7 +
 sound/virtio/virtio_card.c  | 415 
 sound/virtio/virtio_card.h  |  76 ++
 8 files changed, 882 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 00836f6452f0..3f509d54a457 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18936,6 +18936,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 
+M: "Michael S. Tsirkin" 
+L: virtualizat...@lists.linux-foundation.org
+L: alsa-de...@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 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..1ff6310e54d6
--- /dev/null
+++ b/include/uapi/linux/virtio_snd.h
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This header is BSD licensed so anyone can use the definitions to
+ * implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *notice, this list of conditions and the following disclaimer in the
+ *documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of OpenSynergy GmbH nor the names of its contributors
+ *may be used to endorse or promote products derived from this software
+ *without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef VIRTIO_SND_IF_H
+#define VIRTIO_SND_IF_H
+
+#include 
+
+/***
+ * 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_DI

Re: [PATCH 5/7] ALSA: virtio: PCM substream operators

2021-01-24 Thread Anton Yakovlev




On 20.01.2021 09:36, Michael S. Tsirkin wrote:

CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know 
the content is safe.


On Wed, Jan 20, 2021 at 01:36:33AM +0100, Anton Yakovlev wrote:

Introduce the operators required for the operation of substreams.

Signed-off-by: Anton Yakovlev 
---
  sound/virtio/Makefile |   3 +-
  sound/virtio/virtio_pcm.c |   5 +-
  sound/virtio/virtio_pcm.h |   2 +
  sound/virtio/virtio_pcm_ops.c | 509 ++
  4 files changed, 517 insertions(+), 2 deletions(-)
  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 1ab50dcc88c8..6a1ca6b2c3ca 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -121,7 +121,8 @@ static int virtsnd_pcm_build_hw(struct virtio_pcm_substream 
*substream,
   SNDRV_PCM_INFO_MMAP_VALID |
   SNDRV_PCM_INFO_BATCH |
   SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_INTERLEAVED;
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE;

   if (!info->channels_min || info->channels_min > info->channels_max) {
   dev_err(>dev,
@@ -503,6 +504,8 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd)
   if (rc)
   return rc;
   }
+
+ snd_pcm_set_ops(pcm->pcm, i, _pcm_ops);
   }

   return 0;
diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h
index d011b7e1d18d..fe467bc05d8b 100644
--- a/sound/virtio/virtio_pcm.h
+++ b/sound/virtio/virtio_pcm.h
@@ -90,6 +90,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 ..8d26c1144ad6
--- /dev/null
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include 
+
+#include "virtio_card.h"
+
+/*
+ * Our main concern here is maintaining the correct state of the underlying I/O
+ * virtqueues. Thus, operators are implemented to support all of the following
+ * possible control paths (excluding all trivial ones):
+ *
+ *+-+
+ *| open()  |<--+
+ *+++   |
+ * v|
+ *  +--+--+ |
+ *   +->| hw_params() |<-+  |
+ *   |  +-+  |  |
+ *   | v |  |
+ *   |   +---+   |  |
+ *   |   | prepare() |<---+  |  |
+ *   |   +---+|  |  |
+ *   | v  |  |  |
+ *   |+-+ |  |  |
+ * +---+  | trigger(START/  | |  |  |
+ * | restore() |  | PAUSE_RELEASE/  |<-+  |  |  |
+ * +---+  | RESUME) |  |  |  |  |
+ *   ^+-+  |  |  |  |
+ *   | v   |  |  |  |
+ *   |   +---+ |  |  |  |
+ *   |   | pointer() | |  |  |  |
+ *   |   +---+ |  |  |  |
+ *   | v   |  |  |  |
+ *   |  +-+ 

Re: [PATCH 4/7] ALSA: virtio: handling control and I/O messages for the PCM device

2021-01-24 Thread Anton Yakovlev




On 20.01.2021 09:29, Michael S. Tsirkin wrote:

CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know 
the content is safe.


On Wed, Jan 20, 2021 at 01:36:32AM +0100, Anton Yakovlev wrote:

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 expired 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.

When an I/O message is completed, the hw_ptr value is incremented
unconditionally (to ensure that the hw_ptr always correctly reflects
the state of the messages in the virtqueue). Due to its asynchronous
nature, a message can be completed when the runtime structure no longer
exists. For this reason, the values from this structure are cached in
the virtio substream, which are required to calculate the new value of
the hw_ptr.

Signed-off-by: Anton Yakovlev 
---
  sound/virtio/Makefile |   3 +-
  sound/virtio/virtio_card.c|  33 
  sound/virtio/virtio_card.h|   9 +
  sound/virtio/virtio_pcm.c |   3 +
  sound/virtio/virtio_pcm.h |  31 
  sound/virtio/virtio_pcm_msg.c | 317 ++
  6 files changed, 395 insertions(+), 1 deletion(-)
  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 293d497f24e7..dc703fc662f5 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -145,6 +145,12 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
   callbacks[VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb;
   callbacks[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb;

+ virtio_cread(vdev, struct virtio_snd_config, streams, );
+ if (n) {
+ callbacks[VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb;
+ callbacks[VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb;
+ }
+
   rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
NULL);
   if (rc) {
@@ -186,15 +192,42 @@ static int virtsnd_find_vqs(struct virtio_snd *snd)
   * virtsnd_enable_vqs() - Enable the event, tx and rx virtqueues.
   * @snd: VirtIO sound device.
   *
+ * The tx queue is enabled only if the device supports playback stream(s).
+ *
+ * The rx queue is enabled only if the device supports capture stream(s).
+ *
   * Context: Any context.
   */
  static void virtsnd_enable_vqs(struct virtio_snd *snd)
  {
+ struct virtio_device *vdev = snd->vdev;
   struct virtqueue *vqueue;
+ struct virtio_pcm *pcm;
+ unsigned int npbs = 0;
+ unsigned int ncps = 0;

   vqueue = snd->queues[VIRTIO_SND_VQ_EVENT].vqueue;
   if (!virtqueue_enable_cb(vqueue))
   virtsnd_event_notify_cb(vqueue);
+
+ list_for_each_entry(pcm, >pcm_list, list) {
+ npbs += pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].nsubstreams;
+ ncps += pcm->streams[SNDRV_PCM_STREAM_CAPTURE].nsubstreams;
+ }
+
+ if (npbs) {
+ vqueue = snd->queues[VIRTIO_SND_VQ_TX].vqueue;
+ if (!virtqueue_enable_cb(vqueue))
+ dev_warn(>dev,
+  "suspicious notification in the TX queue\n");
+ }
+
+ if (ncps) {
+ vqueue = snd->queues[VIRTIO_SND_VQ_RX].vqueue;
+ if (!virtqueue_enable_cb(vqueue))
+ dev_warn(>dev,
+  "suspicious notification in the RX queue\n");
+ }


Not sure how all this prevents use of same vq from multiple threads ...
And why are we sure there are no buffers yet?  If that is because
nothing yet happened, then I'd also like to point out that a vq starts
out with callbacks enabled, so you don't need to do that first thing ...


Yes, I redone that logic in v2.



  }

  /**
diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h
index be6651a6aaf8..b11c09984882 100644
--- a/sound/virtio/virtio_card.h
+++ b/sound/virtio/virtio_card.h
@@ -89,4 +89,13 @@ virtsnd_rx_queue(struct virtio_snd *snd)
   return >queues[VIRTIO_SND_VQ_RX];
  }

+static inline struct virtio_snd_queue *
+virtsnd_pcm_queue(struct virtio_pcm_subst

Re: [PATCH 3/7] ALSA: virtio: add virtio sound driver

2021-01-24 Thread Anton Yakovlev




On 20.01.2021 09:26, Michael S. Tsirkin wrote:

CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know 
the content is safe.


On Wed, Jan 20, 2021 at 01:36:31AM +0100, Anton Yakovlev wrote:

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. Also, handling DEVICE_NEEDS_RESET device
status.

Signed-off-by: Anton Yakovlev 
---
  MAINTAINERS   |   2 +
  sound/Kconfig |   2 +
  sound/Makefile|   3 +-
  sound/virtio/Kconfig  |  10 +
  sound/virtio/Makefile |   9 +
  sound/virtio/virtio_card.c| 473 ++
  sound/virtio/virtio_card.h|  92 ++
  sound/virtio/virtio_ctl_msg.c | 293 +++
  sound/virtio/virtio_ctl_msg.h | 122 
  sound/virtio/virtio_pcm.c | 536 ++
  sound/virtio/virtio_pcm.h |  89 ++
  11 files changed, 1630 insertions(+), 1 deletion(-)
  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
  create mode 100644 sound/virtio/virtio_ctl_msg.c
  create mode 100644 sound/virtio/virtio_ctl_msg.h
  create mode 100644 sound/virtio/virtio_pcm.c
  create mode 100644 sound/virtio/virtio_pcm.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6dfd59eafe82..8a0e9f04402f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18939,8 +18939,10 @@ F:   include/uapi/linux/virtio_mem.h
  VIRTIO SOUND DRIVER
  M:   Anton Yakovlev 
  L:   virtualizat...@lists.linux-foundation.org
+L:   alsa-de...@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 
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 ..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 ..69162a545a41
--- /dev/null
+++ b/sound/virtio/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o
+
+virtio_snd-objs := \
+ virtio_card.o \
+ virtio_ctl_msg.o \
+ virtio_pcm.o
+
diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
new file mode 100644
index ..293d497f24e7
--- /dev/null
+++ b/sound/virtio/virtio_card.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sound card driver for virtio
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "virtio_card.h"
+
+int msg_timeout_ms = MSEC_PER_SEC;
+module_param(msg_timeout_ms, int, 0644);
+MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
+
+static int virtsnd_pro

Re: [PATCH 2/7] uapi: virtio_snd: add the sound device header file

2021-01-24 Thread Anton Yakovlev

Hello, Michael.

Thanks you for your comments!


On 20.01.2021 09:19, Michael S. Tsirkin wrote:

CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know 
the content is safe.


On Wed, Jan 20, 2021 at 01:36:30AM +0100, Anton Yakovlev wrote:

The file contains the definitions for the sound device from the OASIS
virtio spec.

Signed-off-by: Anton Yakovlev 
---
  MAINTAINERS |   6 +
  include/uapi/linux/virtio_snd.h | 361 
  2 files changed, 367 insertions(+)
  create mode 100644 include/uapi/linux/virtio_snd.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 00836f6452f0..6dfd59eafe82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18936,6 +18936,12 @@ 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 
+L:   virtualizat...@lists.linux-foundation.org
+S:   Maintained
+F:   include/uapi/linux/virtio_snd.h
+
  VIRTUAL BOX GUEST DEVICE DRIVER
  M:   Hans de Goede 
  M:   Arnd Bergmann 


You want sound/virtio here too, right?
I'd just squash this with the next patch in series.


Yes, I squashed these two in v2 and added you to the MAINTAINERS.



diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..1ff6310e54d6
--- /dev/null
+++ b/include/uapi/linux/virtio_snd.h
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This header is BSD licensed so anyone can use the definitions to
+ * implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *notice, this list of conditions and the following disclaimer in the
+ *documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of OpenSynergy GmbH nor the names of its contributors
+ *may be used to endorse or promote products derived from this software
+ *without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef VIRTIO_SND_IF_H
+#define VIRTIO_SND_IF_H
+
+#include 
+
+/***
+ * 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

[PATCH 0/7] ALSA: add virtio sound driver

2021-01-19 Thread Anton Yakovlev
This series implements a driver part of the virtio sound device
specification v8 [1].

The driver supports PCM playback and capture substreams, jack and
channel map controls. A message-based transport is used to write/read
PCM frames to/from a device.

The series is based (and was actually tested) on Linus's master
branch [2], on top of

commit 1e2a199f6ccd ("Merge tag 'spi-fix-v5.11-rc4' of ...")

As a device part was used OpenSynergy proprietary implementation.

Any comments are very welcome.

[1] https://lists.oasis-open.org/archives/virtio-dev/202003/msg00185.html
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Anton Yakovlev (7):
  uapi: virtio_ids: add a sound device type ID from OASIS spec
  uapi: virtio_snd: add the sound device header file
  ALSA: virtio: add virtio sound driver
  ALSA: virtio: handling control and I/O messages for the PCM device
  ALSA: virtio: PCM substream operators
  ALSA: virtio: introduce jack support
  ALSA: virtio: introduce device suspend/resume support

 MAINTAINERS |   8 +
 include/uapi/linux/virtio_ids.h |   1 +
 include/uapi/linux/virtio_snd.h | 361 +++
 sound/Kconfig   |   2 +
 sound/Makefile  |   3 +-
 sound/virtio/Kconfig|  10 +
 sound/virtio/Makefile   |  13 +
 sound/virtio/virtio_card.c  | 593 
 sound/virtio/virtio_card.h  | 121 +++
 sound/virtio/virtio_chmap.c | 237 +
 sound/virtio/virtio_ctl_msg.c   | 293 
 sound/virtio/virtio_ctl_msg.h   | 122 +++
 sound/virtio/virtio_jack.c  | 255 ++
 sound/virtio/virtio_pcm.c   | 582 +++
 sound/virtio/virtio_pcm.h   | 132 +++
 sound/virtio/virtio_pcm_msg.c   | 317 +
 sound/virtio/virtio_pcm_ops.c   | 524 
 17 files changed, 3573 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
 create mode 100644 sound/virtio/virtio_chmap.c
 create mode 100644 sound/virtio/virtio_ctl_msg.c
 create mode 100644 sound/virtio/virtio_ctl_msg.h
 create mode 100644 sound/virtio/virtio_jack.c
 create mode 100644 sound/virtio/virtio_pcm.c
 create mode 100644 sound/virtio/virtio_pcm.h
 create mode 100644 sound/virtio/virtio_pcm_msg.c
 create mode 100644 sound/virtio/virtio_pcm_ops.c

-- 
2.30.0




[PATCH 1/7] uapi: virtio_ids: add a sound device type ID from OASIS spec

2021-01-19 Thread Anton Yakovlev
The OASIS virtio spec defines a sound device type ID that is not
present in the header yet.

Signed-off-by: Anton Yakovlev 
---
 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 bc1c0621f5ed..029a2e07a7f9 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -51,6 +51,7 @@
 #define VIRTIO_ID_PSTORE   22 /* virtio pstore device */
 #define VIRTIO_ID_IOMMU23 /* virtio IOMMU */
 #define VIRTIO_ID_MEM  24 /* virtio mem */
+#define VIRTIO_ID_SOUND25 /* 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 */
-- 
2.30.0




[PATCH 2/7] uapi: virtio_snd: add the sound device header file

2021-01-19 Thread Anton Yakovlev
The file contains the definitions for the sound device from the OASIS
virtio spec.

Signed-off-by: Anton Yakovlev 
---
 MAINTAINERS |   6 +
 include/uapi/linux/virtio_snd.h | 361 
 2 files changed, 367 insertions(+)
 create mode 100644 include/uapi/linux/virtio_snd.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 00836f6452f0..6dfd59eafe82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18936,6 +18936,12 @@ 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 
+L: virtualizat...@lists.linux-foundation.org
+S: Maintained
+F: include/uapi/linux/virtio_snd.h
+
 VIRTUAL BOX GUEST DEVICE DRIVER
 M: Hans de Goede 
 M: Arnd Bergmann 
diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h
new file mode 100644
index ..1ff6310e54d6
--- /dev/null
+++ b/include/uapi/linux/virtio_snd.h
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (C) 2020  OpenSynergy GmbH
+ *
+ * This header is BSD licensed so anyone can use the definitions to
+ * implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *notice, this list of conditions and the following disclaimer in the
+ *documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of OpenSynergy GmbH nor the names of its contributors
+ *may be used to endorse or promote products derived from this software
+ *without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef VIRTIO_SND_IF_H
+#define VIRTIO_SND_IF_H
+
+#include 
+
+/***
+ * 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

  1   2   3   4   5   6   7   8   9   10   >