diff mbox

[v2,1/5] ALSA: xen-front: Introduce Xen para-virtualized sound frontend driver

Message ID 20180416062453.24743-2-andr2000@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Oleksandr Andrushchenko April 16, 2018, 6:24 a.m. UTC
From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Introduce skeleton of the para-virtualized Xen sound
frontend driver.

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to
the state diagram and recovery flow from sound para-virtualized
protocol: xen/interface/io/sndif.h.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
---
 sound/Kconfig             |   2 +
 sound/Makefile            |   2 +-
 sound/xen/Kconfig         |  10 +++
 sound/xen/Makefile        |   5 ++
 sound/xen/xen_snd_front.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/xen/xen_snd_front.h |  18 +++++
 6 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 sound/xen/Kconfig
 create mode 100644 sound/xen/Makefile
 create mode 100644 sound/xen/xen_snd_front.c
 create mode 100644 sound/xen/xen_snd_front.h

Comments

Jürgen Groß April 16, 2018, 12:25 p.m. UTC | #1
On 16/04/18 08:24, Oleksandr Andrushchenko wrote:
> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> 
> Introduce skeleton of the para-virtualized Xen sound
> frontend driver.
> 
> Initial handling for Xen bus states: implement
> Xen bus state machine for the frontend driver according to
> the state diagram and recovery flow from sound para-virtualized
> protocol: xen/interface/io/sndif.h.
> 
> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Only one minor nit (see below). With that addressed (or fixed when
committing):

Reviewed-by: Juergen Gross <jgross@suse.com>


Juergen

> ---
>  sound/Kconfig             |   2 +
>  sound/Makefile            |   2 +-
>  sound/xen/Kconfig         |  10 +++
>  sound/xen/Makefile        |   5 ++
>  sound/xen/xen_snd_front.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++
>  sound/xen/xen_snd_front.h |  18 +++++
>  6 files changed, 232 insertions(+), 1 deletion(-)
>  create mode 100644 sound/xen/Kconfig
>  create mode 100644 sound/xen/Makefile
>  create mode 100644 sound/xen/xen_snd_front.c
>  create mode 100644 sound/xen/xen_snd_front.h
> 
> diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c
> new file mode 100644
> index 000000000000..f406a8f52c51
> --- /dev/null
> +++ b/sound/xen/xen_snd_front.c
> @@ -0,0 +1,196 @@
> +static void sndback_changed(struct xenbus_device *xb_dev,
> +			    enum xenbus_state backend_state)
> +{
> +	struct xen_snd_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
> +	int ret;
> +
> +	dev_dbg(&xb_dev->dev, "Backend state is %s, front is %s\n",
> +		xenbus_strstate(backend_state),
> +		xenbus_strstate(xb_dev->state));
> +
> +	switch (backend_state) {
> +	case XenbusStateReconfiguring:
> +		/* fall through */
> +	case XenbusStateReconfigured:
> +		/* fall through */
> +	case XenbusStateInitialised:
> +		/* fall through */
> +		break;
> +
> +	case XenbusStateInitialising:
> +		/* recovering after backend unexpected closure */
> +		sndback_disconnect(front_info);
> +		break;
> +
> +	case XenbusStateInitWait:
> +		/* recovering after backend unexpected closure */
> +		sndback_disconnect(front_info);
> +
> +		ret = sndback_initwait(front_info);
> +		if (ret < 0)
> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
> +		else
> +			xenbus_switch_state(xb_dev, XenbusStateInitialised);
> +		break;
> +
> +	case XenbusStateConnected:
> +		if (xb_dev->state != XenbusStateInitialised)
> +			break;
> +
> +		ret = sndback_connect(front_info);
> +		if (ret < 0)
> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
> +		else
> +			xenbus_switch_state(xb_dev, XenbusStateConnected);
> +		break;
> +
> +	case XenbusStateClosing:
> +		/*
> +		 * in this state backend starts freeing resources,
> +		 * so let it go into closed state first, so we can also
> +		 * remove ours
> +		 */

Please start the sentence with a capital letter and end it with a
full stop.


Juergen
Oleksandr Andrushchenko April 17, 2018, 8:24 a.m. UTC | #2
On 04/16/2018 03:25 PM, Juergen Gross wrote:
> On 16/04/18 08:24, Oleksandr Andrushchenko wrote:
>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
>>
>> Introduce skeleton of the para-virtualized Xen sound
>> frontend driver.
>>
>> Initial handling for Xen bus states: implement
>> Xen bus state machine for the frontend driver according to
>> the state diagram and recovery flow from sound para-virtualized
>> protocol: xen/interface/io/sndif.h.
>>
>> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Only one minor nit (see below). With that addressed (or fixed when
> committing):
will fix
> Reviewed-by: Juergen Gross <jgross@suse.com>
Thank you
>
> Juergen
>
>> ---
>>   sound/Kconfig             |   2 +
>>   sound/Makefile            |   2 +-
>>   sound/xen/Kconfig         |  10 +++
>>   sound/xen/Makefile        |   5 ++
>>   sound/xen/xen_snd_front.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++
>>   sound/xen/xen_snd_front.h |  18 +++++
>>   6 files changed, 232 insertions(+), 1 deletion(-)
>>   create mode 100644 sound/xen/Kconfig
>>   create mode 100644 sound/xen/Makefile
>>   create mode 100644 sound/xen/xen_snd_front.c
>>   create mode 100644 sound/xen/xen_snd_front.h
>>
>> diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c
>> new file mode 100644
>> index 000000000000..f406a8f52c51
>> --- /dev/null
>> +++ b/sound/xen/xen_snd_front.c
>> @@ -0,0 +1,196 @@
>> +static void sndback_changed(struct xenbus_device *xb_dev,
>> +			    enum xenbus_state backend_state)
>> +{
>> +	struct xen_snd_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
>> +	int ret;
>> +
>> +	dev_dbg(&xb_dev->dev, "Backend state is %s, front is %s\n",
>> +		xenbus_strstate(backend_state),
>> +		xenbus_strstate(xb_dev->state));
>> +
>> +	switch (backend_state) {
>> +	case XenbusStateReconfiguring:
>> +		/* fall through */
>> +	case XenbusStateReconfigured:
>> +		/* fall through */
>> +	case XenbusStateInitialised:
>> +		/* fall through */
>> +		break;
>> +
>> +	case XenbusStateInitialising:
>> +		/* recovering after backend unexpected closure */
>> +		sndback_disconnect(front_info);
>> +		break;
>> +
>> +	case XenbusStateInitWait:
>> +		/* recovering after backend unexpected closure */
>> +		sndback_disconnect(front_info);
>> +
>> +		ret = sndback_initwait(front_info);
>> +		if (ret < 0)
>> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
>> +		else
>> +			xenbus_switch_state(xb_dev, XenbusStateInitialised);
>> +		break;
>> +
>> +	case XenbusStateConnected:
>> +		if (xb_dev->state != XenbusStateInitialised)
>> +			break;
>> +
>> +		ret = sndback_connect(front_info);
>> +		if (ret < 0)
>> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
>> +		else
>> +			xenbus_switch_state(xb_dev, XenbusStateConnected);
>> +		break;
>> +
>> +	case XenbusStateClosing:
>> +		/*
>> +		 * in this state backend starts freeing resources,
>> +		 * so let it go into closed state first, so we can also
>> +		 * remove ours
>> +		 */
> Please start the sentence with a capital letter and end it with a
> full stop.
>
>
> Juergen
Takashi Iwai April 24, 2018, 1:55 p.m. UTC | #3
On Mon, 16 Apr 2018 08:24:49 +0200,
Oleksandr Andrushchenko wrote:
> --- /dev/null
> +++ b/sound/xen/Kconfig
> @@ -0,0 +1,10 @@
> +# ALSA Xen drivers
> +
> +config SND_XEN_FRONTEND
> +	tristate "Xen para-virtualized sound frontend driver"
> +	depends on XEN && SND_PCM

Please do select SND_PCM instead of depends.

> +	select XEN_XENBUS_FRONTEND
> +	default n

"default n" is superfluous, drop it.


thanks,

Takashi
Oleksandr Andrushchenko April 24, 2018, 1:59 p.m. UTC | #4
On 04/24/2018 04:55 PM, Takashi Iwai wrote:
> On Mon, 16 Apr 2018 08:24:49 +0200,
> Oleksandr Andrushchenko wrote:
>> --- /dev/null
>> +++ b/sound/xen/Kconfig
>> @@ -0,0 +1,10 @@
>> +# ALSA Xen drivers
>> +
>> +config SND_XEN_FRONTEND
>> +	tristate "Xen para-virtualized sound frontend driver"
>> +	depends on XEN && SND_PCM
> Please do select SND_PCM instead of depends.
will do
>> +	select XEN_XENBUS_FRONTEND
>> +	default n
> "default n" is superfluous, drop it.
will drop
>
> thanks,
>
> Takashi
Thank you,
Oleksandr
diff mbox

Patch

diff --git a/sound/Kconfig b/sound/Kconfig
index 6833db9002ec..1140e9988fc5 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -96,6 +96,8 @@  source "sound/x86/Kconfig"
 
 source "sound/synth/Kconfig"
 
+source "sound/xen/Kconfig"
+
 endif # SND
 
 endif # !UML
diff --git a/sound/Makefile b/sound/Makefile
index 99d8c31262c8..797ecdcd35e2 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@ 
 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/
+	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
diff --git a/sound/xen/Kconfig b/sound/xen/Kconfig
new file mode 100644
index 000000000000..7cad38be8317
--- /dev/null
+++ b/sound/xen/Kconfig
@@ -0,0 +1,10 @@ 
+# ALSA Xen drivers
+
+config SND_XEN_FRONTEND
+	tristate "Xen para-virtualized sound frontend driver"
+	depends on XEN && SND_PCM
+	select XEN_XENBUS_FRONTEND
+	default n
+	help
+	  Choose this option if you want to enable a para-virtualized
+	  frontend sound driver for Xen guest OSes.
diff --git a/sound/xen/Makefile b/sound/xen/Makefile
new file mode 100644
index 000000000000..4507ef3c27fd
--- /dev/null
+++ b/sound/xen/Makefile
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: GPL-2.0 OR MIT
+
+snd_xen_front-objs := xen_snd_front.o
+
+obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o
diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c
new file mode 100644
index 000000000000..f406a8f52c51
--- /dev/null
+++ b/sound/xen/xen_snd_front.c
@@ -0,0 +1,196 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+/*
+ * Xen para-virtual sound device
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <xen/platform_pci.h>
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+
+#include <xen/interface/io/sndif.h>
+
+#include "xen_snd_front.h"
+
+static void xen_snd_drv_fini(struct xen_snd_front_info *front_info)
+{
+}
+
+static int sndback_initwait(struct xen_snd_front_info *front_info)
+{
+	return 0;
+}
+
+static int sndback_connect(struct xen_snd_front_info *front_info)
+{
+	return 0;
+}
+
+static void sndback_disconnect(struct xen_snd_front_info *front_info)
+{
+	xen_snd_drv_fini(front_info);
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
+static void sndback_changed(struct xenbus_device *xb_dev,
+			    enum xenbus_state backend_state)
+{
+	struct xen_snd_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	dev_dbg(&xb_dev->dev, "Backend state is %s, front is %s\n",
+		xenbus_strstate(backend_state),
+		xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		/* fall through */
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		sndback_disconnect(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		sndback_disconnect(front_info);
+
+		ret = sndback_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = sndback_connect(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state first, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		sndback_disconnect(front_info);
+		break;
+	}
+}
+
+static int xen_drv_probe(struct xenbus_device *xb_dev,
+			 const struct xenbus_device_id *id)
+{
+	struct xen_snd_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+				  sizeof(*front_info), GFP_KERNEL);
+	if (!front_info)
+		return -ENOMEM;
+
+	front_info->xb_dev = xb_dev;
+	dev_set_drvdata(&xb_dev->dev, front_info);
+
+	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
+}
+
+static int xen_drv_remove(struct xenbus_device *dev)
+{
+	struct xen_snd_front_info *front_info = dev_get_drvdata(&dev->dev);
+	int to = 100;
+
+	xenbus_switch_state(dev, XenbusStateClosing);
+
+	/*
+	 * On driver removal it is disconnected from XenBus,
+	 * so no backend state change events come via .otherend_changed
+	 * callback. This prevents us from exiting gracefully, e.g.
+	 * signaling the backend to free event channels, waiting for its
+	 * state to change to XenbusStateClosed and cleaning at our end.
+	 * Normally when front driver removed backend will finally go into
+	 * XenbusStateInitWait state.
+	 *
+	 * Workaround: read backend's state manually and wait with time-out.
+	 */
+	while ((xenbus_read_unsigned(front_info->xb_dev->otherend, "state",
+				     XenbusStateUnknown) != XenbusStateInitWait) &&
+				     to--)
+		msleep(10);
+
+	if (!to) {
+		unsigned int state;
+
+		state = xenbus_read_unsigned(front_info->xb_dev->otherend,
+					     "state", XenbusStateUnknown);
+		pr_err("Backend state is %s while removing driver\n",
+		       xenbus_strstate(state));
+	}
+
+	xen_snd_drv_fini(front_info);
+	xenbus_frontend_closed(dev);
+	return 0;
+}
+
+static const struct xenbus_device_id xen_drv_ids[] = {
+	{ XENSND_DRIVER_NAME },
+	{ "" }
+};
+
+static struct xenbus_driver xen_driver = {
+	.ids = xen_drv_ids,
+	.probe = xen_drv_probe,
+	.remove = xen_drv_remove,
+	.otherend_changed = sndback_changed,
+};
+
+static int __init xen_drv_init(void)
+{
+	if (!xen_domain())
+		return -ENODEV;
+
+	if (!xen_has_pv_devices())
+		return -ENODEV;
+
+	pr_info("Initialising Xen " XENSND_DRIVER_NAME " frontend driver\n");
+	return xenbus_register_frontend(&xen_driver);
+}
+
+static void __exit xen_drv_fini(void)
+{
+	pr_info("Unregistering Xen " XENSND_DRIVER_NAME " frontend driver\n");
+	xenbus_unregister_driver(&xen_driver);
+}
+
+module_init(xen_drv_init);
+module_exit(xen_drv_fini);
+
+MODULE_DESCRIPTION("Xen virtual sound device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:" XENSND_DRIVER_NAME);
+MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual soundcard}}");
diff --git a/sound/xen/xen_snd_front.h b/sound/xen/xen_snd_front.h
new file mode 100644
index 000000000000..4ae204b23d32
--- /dev/null
+++ b/sound/xen/xen_snd_front.h
@@ -0,0 +1,18 @@ 
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+
+/*
+ * Xen para-virtual sound device
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
+ */
+
+#ifndef __XEN_SND_FRONT_H
+#define __XEN_SND_FRONT_H
+
+struct xen_snd_front_info {
+	struct xenbus_device *xb_dev;
+};
+
+#endif /* __XEN_SND_FRONT_H */