linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Introduce userspace-driven ALSA timers
@ 2024-08-06 12:52 Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 1/4] ALSA: aloop: Allow using global timers Ivan Orlov
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 12:52 UTC (permalink / raw)
  To: perex, tiwai, corbet, broonie, shuah
  Cc: Ivan Orlov, linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

There are multiple possible timer sources which could be useful for
the sound stream synchronization: hrtimers, hardware clocks (e.g. PTP),
timer wheels (jiffies). Currently, using one of them to synchronize
the audio stream of snd-aloop module would require writing a
kernel-space driver which exports an ALSA timer through the
snd_timer interface.

However, it is not really convenient for application developers, who may
want to define their custom timer sources for audio synchronization.

For instance, we could have a network application which receives frames
and sends them to snd-aloop pcm device, and another application
listening on the other end of snd-aloop. It makes sense to transfer a
new period of data only when certain amount of frames is received
through the network, but definitely not when a certain amount of jiffies
on a local system elapses. Since all of the devices are purely virtual
it won't introduce any glitches and will help the application developers
to avoid using sample-rate conversion.

This patch series introduces userspace-driven ALSA timers: virtual
timers which are created and controlled from userspace. The timer can
be created from the userspace using the new ioctl SNDRV_TIMER_IOCTL_CREATE.
After creating a timer, it becomes available for use system-wide, so it
can be passed to snd-aloop as a timer source (timer_source parameter
would be "-1.SNDRV_TIMER_GLOBAL_UDRIVEN.{timer_id}"). When the userspace
app decides to trigger a timer, it calls another ioctl
SNDRV_TIMER_IOCTL_TRIGGER on the file descriptor of a timer. It
initiates a transfer of a new period of data.

Userspace-driven timers are associated with file descriptors. If the
application wishes to destroy the timer, it can simply release the file
descriptor of a virtual timer.

I believe introducing new ioctl calls is quite inconvenient (as we have
a limited amount of them), but other possible ways of app <-> kernel
communication (like virtual FS) seem completely inappropriate for this
task (but I'd love to discuss alternative solutions).

This patch series also updates the snd-aloop module so the global timers
can be used as a timer_source for it (it allows using userspace-driven
timers as timer source).

V1 -> V2:
- Fix some problems found by Christophe Jaillet
<christophe.jaillet@wanadoo.fr>
V2 -> V3:
- Add improvements suggested by Takashi Iwai <tiwai@suse.de>

Please, find the patch-specific changelog in the following patches.

Ivan Orlov (4):
  ALSA: aloop: Allow using global timers
  Docs/sound: Add documentation for userspace-driven ALSA timers
  ALSA: timer: Introduce virtual userspace-driven timers
  selftests: ALSA: Cover userspace-driven timers with test

 Documentation/sound/index.rst               |   1 +
 Documentation/sound/utimers.rst             | 120 +++++++++++
 include/uapi/sound/asound.h                 |  20 +-
 sound/core/Kconfig                          |  10 +
 sound/core/timer.c                          | 221 ++++++++++++++++++++
 sound/drivers/aloop.c                       |   2 +
 tools/testing/selftests/alsa/Makefile       |   2 +-
 tools/testing/selftests/alsa/global-timer.c |  87 ++++++++
 tools/testing/selftests/alsa/utimer-test.c  | 170 +++++++++++++++
 9 files changed, 631 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/sound/utimers.rst
 create mode 100644 tools/testing/selftests/alsa/global-timer.c
 create mode 100644 tools/testing/selftests/alsa/utimer-test.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/4] ALSA: aloop: Allow using global timers
  2024-08-06 12:52 [PATCH v3 0/4] Introduce userspace-driven ALSA timers Ivan Orlov
@ 2024-08-06 12:52 ` Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 2/4] Docs/sound: Add documentation for userspace-driven ALSA timers Ivan Orlov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 12:52 UTC (permalink / raw)
  To: perex, tiwai, corbet, broonie, shuah
  Cc: Ivan Orlov, linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

Allow using global timers as a timer source when card id is equal to -1
in the timer_source parameter.

Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com>
---
V1 -> V2:
- No changes
V2 -> V3:
- No changes

 sound/drivers/aloop.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index d6dd4b8c750a..a1e5e7fe9c72 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -1130,6 +1130,8 @@ static int loopback_parse_timer_id(const char *str,
 			}
 		}
 	}
+	if (card_idx == -1)
+		tid->dev_class = SNDRV_TIMER_CLASS_GLOBAL;
 	if (!err && tid) {
 		tid->card = card_idx;
 		tid->device = dev;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/4] Docs/sound: Add documentation for userspace-driven ALSA timers
  2024-08-06 12:52 [PATCH v3 0/4] Introduce userspace-driven ALSA timers Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 1/4] ALSA: aloop: Allow using global timers Ivan Orlov
@ 2024-08-06 12:52 ` Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test Ivan Orlov
  3 siblings, 0 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 12:52 UTC (permalink / raw)
  To: perex, tiwai, corbet, broonie, shuah
  Cc: Ivan Orlov, linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

Add the documentation which describes the new userspace-driven timers
API introduced in this patch series. The documentation contains:

- Description of userspace-driven ALSA timers, what they are for
- Description of the timers API
- Example of how the timers can be created and triggered
- How the timers can be used as a timer sources for snd-aloop module

Suggested-by: Axel Holzinger <aholzinger@gmx.de>
Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com>
---
V1 -> V2:
- No changes
V2 -> V3:
- No changes

 Documentation/sound/index.rst   |   1 +
 Documentation/sound/utimers.rst | 120 ++++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+)
 create mode 100644 Documentation/sound/utimers.rst

diff --git a/Documentation/sound/index.rst b/Documentation/sound/index.rst
index 7e67e12730d3..c437f2a4bc85 100644
--- a/Documentation/sound/index.rst
+++ b/Documentation/sound/index.rst
@@ -13,6 +13,7 @@ Sound Subsystem Documentation
    alsa-configuration
    hd-audio/index
    cards/index
+   utimers
 
 .. only::  subproject and html
 
diff --git a/Documentation/sound/utimers.rst b/Documentation/sound/utimers.rst
new file mode 100644
index 000000000000..0bd875ea9986
--- /dev/null
+++ b/Documentation/sound/utimers.rst
@@ -0,0 +1,120 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================
+Userspace-driven timers
+=======================
+
+:Author: Ivan Orlov <ivan.orlov0322@gmail.com>
+
+Preface
+=======
+
+This document describes the userspace-driven timers: virtual ALSA timers
+which could be created and controlled by userspace applications using
+IOCTL calls. Such timers could be useful when synchronizing audio
+stream with timer sources which we don't have ALSA timers exported for
+(e.g. PTP clocks), and when synchronizing the audio stream going through
+two virtual sound devices using ``snd-aloop`` (for instance, when
+we have a network application sending frames to one snd-aloop device,
+and another sound application listening on the other end of snd-aloop).
+
+Enabling userspace-driven timers
+================================
+
+The userspace-driven timers could be enabled in the kernel using the
+``CONFIG_SND_UTIMER`` configuration option. It depends on the
+``CONFIG_SND_TIMER`` option, so it also should be enabled.
+
+Userspace-driven timers API
+===========================
+
+Userspace application can create a userspace-driven ALSA timer by
+executing the ``SNDRV_TIMER_IOCTL_CREATE`` ioctl call on the
+``/dev/snd/timer`` device file descriptor. The ``snd_utimer_info``
+structure should be passed as an ioctl argument:
+
+::
+
+    struct snd_utimer_info {
+        snd_pcm_uframes_t frame_rate;
+        snd_pcm_uframes_t period_size;
+        unsigned int id;
+    }
+
+``frame_rate`` and ``period_size`` set the desired frame rate and period
+size emulated by the virtual timer respectively. ``id`` field gets
+overwritten by the ioctl, and the identifier you get in this field after
+the call can be used as a timer subdevice number when passing the timer
+to ``snd-aloop`` kernel module or other userspace applications. There
+could be up to 128 userspace-driven timers in the system at one moment
+of time, thus the id value ranges from 0 to 127.
+
+Besides from overwriting the ``snd_utimer_info`` struct, ioctl returns
+a timer file descriptor, which can be used to trigger the timer. This
+guarantees that the timer can only be triggered by the process which
+created it. The timer then can be triggered with
+``SNDRV_TIMER_IOCTL_TRIGGER`` ioctl call on the timer file descriptor.
+
+So, the example code for creating and triggering the timer would be:
+
+::
+
+    static const struct snd_utimer_info utimer_info = {
+        .frame_rate = 8000,
+        .period_size = 4410,
+        .id = -1,
+    };
+
+    int timer_device_fd = open("/dev/snd/timer",  O_RDWR | O_CLOEXEC);
+    int utimer_fd = ioctl(timer_device_fd, SNDRV_TIMER_IOCTL_CREATE, &utimer_info);
+
+    if (utimer_fd < 0) {
+        perror("Failed to create the timer");
+        return -1;
+    }
+
+    ...
+
+    /*
+     * Now we want to trigger the timer. Callbacks of all of the
+     * timer instances binded to this timer will be executed after
+     * this call.
+     */
+    ioctl(utimer_fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL);
+
+    ...
+
+    /* Now, destroy the timer */
+    close(utimer_fd);
+
+
+More detailed example of creating and ticking the timer could be found
+in the utimer ALSA selftest.
+
+Userspace-driven timers and snd-aloop
+-------------------------------------
+
+Userspace-driven timers could be easily used with ``snd-aloop`` module
+when synchronizing two sound applications on both ends of the virtual
+sound loopback. For instance, if one of the applications receives sound
+frames from network and sends them to snd-aloop pcm device, and another
+application listens for frames on the other snd-aloop pcm device, it
+makes sense that the ALSA middle layer should initiate a data
+transaction when the new period of data is received through network, but
+not when the certain amount of jiffies elapses. Userspace-driven ALSA
+timers could be used to achieve this.
+
+To use userspace-driven ALSA timer as a timer source of snd-aloop, pass
+the following string as the snd-aloop ``timer_source`` parameter:
+
+::
+
+  # modprobe snd-aloop timer_source="-1.4.<utimer_id>"
+
+Where ``utimer_id`` is the id of the timer you created with
+``SNDRV_TIMER_IOCTL_CREATE``, and ``4`` is the number of
+userspace-driven timers device (``SNDRV_TIMER_GLOBAL_UDRIVEN``).
+
+After that, each time you trigger the timer with
+``SNDRV_TIMER_IOCTL_TRIGGER`` the new period of data will be transferred
+from one snd-aloop device to another.
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers
  2024-08-06 12:52 [PATCH v3 0/4] Introduce userspace-driven ALSA timers Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 1/4] ALSA: aloop: Allow using global timers Ivan Orlov
  2024-08-06 12:52 ` [PATCH v3 2/4] Docs/sound: Add documentation for userspace-driven ALSA timers Ivan Orlov
@ 2024-08-06 12:52 ` Ivan Orlov
  2024-08-06 13:11   ` Jaroslav Kysela
  2024-08-08  9:22   ` kernel test robot
  2024-08-06 12:52 ` [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test Ivan Orlov
  3 siblings, 2 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 12:52 UTC (permalink / raw)
  To: perex, tiwai, corbet, broonie, shuah
  Cc: Ivan Orlov, linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

Implement two ioctl calls in order to support virtual userspace-driven
ALSA timers.

The first ioctl is SNDRV_TIMER_IOCTL_CREATE, which gets the
snd_utimer_info struct as a parameter and returns a file descriptor of
a virtual timer. It also updates the `id` field of the snd_utimer_info
struct, which provides a unique identifier for the timer (basically,
the subdevice number which can be used when creating timer instances).

This patch also introduces a tiny id allocator for the userspace-driven
timers, which guarantees that we don't have more than 128 of them in the
system.

Another ioctl is SNDRV_TIMER_IOCTL_TRIGGER, which allows us to trigger
the virtual timer (and calls snd_timer_interrupt for the timer under
the hood), causing all of the timer instances binded to this timer to
execute their callbacks.

The maximum amount of ticks available for the timer is 1 for the sake of
simplification of the userspace API. 'start', 'stop', 'open' and 'close'
callbacks for the userspace-driven timers are empty since we don't
really do any hardware initialization here.

Suggested-by: Axel Holzinger <aholzinger@gmx.de>
Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com>
---
V1 -> V2:
- Add missing kfree for the utimer name in snd_utimer_free
- Remove extra newline in sound core Kconfig
- Use IDA allocator API to allocate utimer ids
- Use kasprintf for the timer name instead of kzalloc + sprintf
V2 -> V3:
- Use __u64 instead of snd_pcm_uframes_t in snd_utimer_info struct
- Add 16 reserved bytes to snd_utimer_info struct just in case we decide
to add some other fields to this struct
- Bump the timer protocol version in SNDRV_TIMER_VERSION to 2.0.8
- Make the 'snd_utimer_ids' variable static
- Add sanity checks to the 'snd_utimer_create' function: 0-check for
period size and frame rate, overflow and 0- checks for resolution
- Use automatic cleanup in 'snd_utimer_ioctl_create'
- Return -ENOTTY instead of -EINVAL from ioctl if userspace-driven
timers are disabled

 include/uapi/sound/asound.h |  20 +++-
 sound/core/Kconfig          |  10 ++
 sound/core/timer.c          | 221 ++++++++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+), 1 deletion(-)

diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 8bf7e8a0eb6f..cdd9cf8f71c1 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -869,7 +869,7 @@ struct snd_ump_block_info {
  *  Timer section - /dev/snd/timer
  */
 
-#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 7)
+#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 8)
 
 enum {
 	SNDRV_TIMER_CLASS_NONE = -1,
@@ -894,6 +894,7 @@ enum {
 #define SNDRV_TIMER_GLOBAL_RTC		1	/* unused */
 #define SNDRV_TIMER_GLOBAL_HPET		2
 #define SNDRV_TIMER_GLOBAL_HRTIMER	3
+#define SNDRV_TIMER_GLOBAL_UDRIVEN	4
 
 /* info flags */
 #define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
@@ -974,6 +975,21 @@ struct snd_timer_status {
 };
 #endif
 
+/*
+ * This structure describes the userspace-driven timer. Such timers are purely virtual,
+ * and can only be triggered from software (for instance, by userspace application).
+ */
+struct snd_utimer_info {
+	/*
+	 * To pretend being a normal timer, we need to know the frame rate and
+	 * the period size in frames.
+	 */
+	__u64 frame_rate;
+	__u64 period_size;
+	unsigned int id;
+	unsigned char reserved[16];
+};
+
 #define SNDRV_TIMER_IOCTL_PVERSION	_IOR('T', 0x00, int)
 #define SNDRV_TIMER_IOCTL_NEXT_DEVICE	_IOWR('T', 0x01, struct snd_timer_id)
 #define SNDRV_TIMER_IOCTL_TREAD_OLD	_IOW('T', 0x02, int)
@@ -990,6 +1006,8 @@ struct snd_timer_status {
 #define SNDRV_TIMER_IOCTL_CONTINUE	_IO('T', 0xa2)
 #define SNDRV_TIMER_IOCTL_PAUSE		_IO('T', 0xa3)
 #define SNDRV_TIMER_IOCTL_TREAD64	_IOW('T', 0xa4, int)
+#define SNDRV_TIMER_IOCTL_CREATE	_IOWR('T', 0xa5, struct snd_utimer_info)
+#define SNDRV_TIMER_IOCTL_TRIGGER	_IO('T', 0xa6)
 
 #if __BITS_PER_LONG == 64
 #define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b970a1734647..670b26cf3065 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -251,6 +251,16 @@ config SND_JACK_INJECTION_DEBUG
 	  Say Y if you are debugging via jack injection interface.
 	  If unsure select "N".
 
+config SND_UTIMER
+	bool "Enable support for userspace-controlled virtual timers"
+	depends on SND_TIMER
+	help
+	  Say Y to enable the support of userspace-controlled timers. These
+	  timers are purely virtual, and they are supposed to be triggered
+	  from userspace. They could be quite useful when synchronizing the
+	  sound timing with userspace applications (for instance, when sending
+	  data through snd-aloop).
+
 config SND_VMASTER
 	bool
 
diff --git a/sound/core/timer.c b/sound/core/timer.c
index d104adc75a8b..dabb925625f1 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -13,6 +13,9 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/sched/signal.h>
+#include <linux/anon_inodes.h>
+#include <linux/idr.h>
+#include <linux/units.h>
 #include <sound/core.h>
 #include <sound/timer.h>
 #include <sound/control.h>
@@ -109,6 +112,16 @@ struct snd_timer_status64 {
 	unsigned char reserved[64];	/* reserved */
 };
 
+#ifdef CONFIG_SND_UTIMER
+#define SNDRV_UTIMERS_MAX_COUNT 128
+/* Internal data structure for keeping the state of the userspace-driven timer */
+struct snd_utimer {
+	char *name;
+	struct snd_timer *timer;
+	unsigned int id;
+};
+#endif
+
 #define SNDRV_TIMER_IOCTL_STATUS64	_IOR('T', 0x14, struct snd_timer_status64)
 
 /* list of timers */
@@ -2009,6 +2022,212 @@ enum {
 	SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
 };
 
+#ifdef CONFIG_SND_UTIMER
+/*
+ * Since userspace-driven timers are passed to userspace, we need to have an identifier
+ * which will allow us to use them (basically, the subdevice number of udriven timer).
+ */
+static DEFINE_IDA(snd_utimer_ids);
+
+static void snd_utimer_put_id(struct snd_utimer *utimer)
+{
+	int timer_id = utimer->id;
+
+	snd_BUG_ON(timer_id < 0 || timer_id >= SNDRV_UTIMERS_MAX_COUNT);
+	ida_free(&snd_utimer_ids, timer_id);
+}
+
+static int snd_utimer_take_id(void)
+{
+	return ida_alloc_max(&snd_utimer_ids, SNDRV_UTIMERS_MAX_COUNT - 1, GFP_KERNEL);
+}
+
+static void snd_utimer_free(struct snd_utimer *utimer)
+{
+	snd_timer_free(utimer->timer);
+	snd_utimer_put_id(utimer);
+	kfree(utimer->name);
+	kfree(utimer);
+}
+
+static int snd_utimer_release(struct inode *inode, struct file *file)
+{
+	struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
+
+	snd_utimer_free(utimer);
+	return 0;
+}
+
+static int snd_utimer_trigger(struct file *file)
+{
+	struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
+
+	snd_timer_interrupt(utimer->timer, utimer->timer->sticks);
+	return 0;
+}
+
+static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
+{
+	switch (ioctl) {
+	case SNDRV_TIMER_IOCTL_TRIGGER:
+		return snd_utimer_trigger(file);
+	}
+
+	return -ENOTTY;
+}
+
+static const struct file_operations snd_utimer_fops = {
+	.llseek = noop_llseek,
+	.release = snd_utimer_release,
+	.unlocked_ioctl = snd_utimer_ioctl,
+};
+
+static int snd_utimer_start(struct snd_timer *t)
+{
+	return 0;
+}
+
+static int snd_utimer_stop(struct snd_timer *t)
+{
+	return 0;
+}
+
+static int snd_utimer_open(struct snd_timer *t)
+{
+	return 0;
+}
+
+static int snd_utimer_close(struct snd_timer *t)
+{
+	return 0;
+}
+
+static const struct snd_timer_hardware timer_hw = {
+	.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
+	.open = snd_utimer_open,
+	.close = snd_utimer_close,
+	.start = snd_utimer_start,
+	.stop = snd_utimer_stop,
+};
+
+static int snd_utimer_create(struct snd_utimer_info *utimer_info,
+			     struct snd_utimer **r_utimer)
+{
+	struct snd_utimer *utimer;
+	struct snd_timer *timer;
+	struct snd_timer_id tid;
+	int utimer_id;
+	int err = 0;
+	u64 resolution;
+
+	if (!utimer_info || utimer_info->frame_rate == 0 || utimer_info->period_size == 0)
+		return -EINVAL;
+
+	/* Let's check that we won't get an overflow in the resolution */
+	if (NANO / utimer_info->frame_rate > U64_MAX / utimer_info->period_size)
+		return -EINVAL;
+
+	resolution = NANO / utimer_info->frame_rate * utimer_info->period_size;
+
+	if (resolution == 0)
+		return -EINVAL;
+
+	utimer = kzalloc(sizeof(*utimer), GFP_KERNEL);
+	if (!utimer)
+		return -ENOMEM;
+
+	/* We hold the ioctl lock here so we won't get a race condition when allocating id */
+	utimer_id = snd_utimer_take_id();
+	if (utimer_id < 0) {
+		err = utimer_id;
+		goto err_take_id;
+	}
+
+	utimer->name = kasprintf(GFP_KERNEL, "snd-utimer%d", utimer_id);
+	if (!utimer->name) {
+		err = -ENOMEM;
+		goto err_get_name;
+	}
+
+	utimer->id = utimer_id;
+
+	tid.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
+	tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
+	tid.card = -1;
+	tid.device = SNDRV_TIMER_GLOBAL_UDRIVEN;
+	tid.subdevice = utimer_id;
+
+	err = snd_timer_new(NULL, utimer->name, &tid, &timer);
+	if (err < 0) {
+		pr_err("Can't create userspace-driven timer\n");
+		goto err_timer_new;
+	}
+
+	timer->module = THIS_MODULE;
+	timer->hw = timer_hw;
+	timer->hw.resolution = resolution;
+	timer->hw.ticks = 1;
+	timer->max_instances = MAX_SLAVE_INSTANCES;
+
+	utimer->timer = timer;
+
+	err = snd_timer_global_register(timer);
+	if (err < 0) {
+		pr_err("Can't register a userspace-driven timer\n");
+		goto err_timer_reg;
+	}
+
+	*r_utimer = utimer;
+	return 0;
+
+err_timer_reg:
+	snd_timer_free(timer);
+err_timer_new:
+	kfree(utimer->name);
+err_get_name:
+	snd_utimer_put_id(utimer);
+err_take_id:
+	kfree(utimer);
+
+	return err;
+}
+
+static int snd_utimer_ioctl_create(struct file *file,
+				   struct snd_utimer_info __user *_utimer_info)
+{
+	struct snd_utimer *utimer;
+	struct snd_utimer_info *utimer_info __free(kfree) = NULL;
+	int err;
+
+	utimer_info = memdup_user(_utimer_info, sizeof(*utimer_info));
+	if (IS_ERR(utimer_info))
+		return PTR_ERR(no_free_ptr(utimer_info));
+
+	err = snd_utimer_create(utimer_info, &utimer);
+	if (err < 0)
+		return err;
+
+	utimer_info->id = utimer->id;
+
+	err = copy_to_user(_utimer_info, utimer_info, sizeof(*utimer_info));
+	if (err) {
+		snd_utimer_free(utimer);
+		return -EFAULT;
+	}
+
+	return anon_inode_getfd(utimer->name, &snd_utimer_fops, utimer, O_RDWR | O_CLOEXEC);
+}
+
+#else
+
+static int snd_utimer_ioctl_create(struct file *file,
+				   struct snd_utimer_info __user *_utimer_info)
+{
+	return -ENOTTY;
+}
+
+#endif
+
 static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
 				 unsigned long arg, bool compat)
 {
@@ -2053,6 +2272,8 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
 	case SNDRV_TIMER_IOCTL_PAUSE:
 	case SNDRV_TIMER_IOCTL_PAUSE_OLD:
 		return snd_timer_user_pause(file);
+	case SNDRV_TIMER_IOCTL_CREATE:
+		return snd_utimer_ioctl_create(file, argp);
 	}
 	return -ENOTTY;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test
  2024-08-06 12:52 [PATCH v3 0/4] Introduce userspace-driven ALSA timers Ivan Orlov
                   ` (2 preceding siblings ...)
  2024-08-06 12:52 ` [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers Ivan Orlov
@ 2024-08-06 12:52 ` Ivan Orlov
  2024-08-06 13:04   ` Mark Brown
  3 siblings, 1 reply; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 12:52 UTC (permalink / raw)
  To: perex, tiwai, corbet, broonie, shuah
  Cc: Ivan Orlov, linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

Add a test for the new functionality of userspace-driven timers and the
tool which allows us to count timer ticks in a certain time period. The
test:

1. Creates a userspace-driven timer with ioctl to /dev/snd/timer
2. Starts the `global-timer` application to count the ticks of the timer
from step 1.
3. Asynchronously triggers the timer multiple times with some interval
4. Compares the amount of caught ticks with the amount of trigger calls.

Since we can't include <alsa/asoundlib.h> and <sound/asound.h> in one
file due to overlapping declarations, I have to split the test into two
applications: one of them counts the amount of timer ticks in the
defined time period, and another one is the actual test which creates
the timer, triggers it periodically and starts the first app to count
the amount of ticks in a separate thread.

Besides from testing the functionality itself, the test represents a
sample application showing userspace-driven ALSA timers API.

Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com>
---
V1 -> V2:
- Return NULL in the pthreaded function (ticking_func)
- Process TIMER_NO_EVENT enum in the timer app output processing loop
V2 -> V3:
- Add new test case to cover invalid period sizes and frame rates for
the userspace-driven timers (to test the sanity checks in
snd_utimer_create)

 tools/testing/selftests/alsa/Makefile       |   2 +-
 tools/testing/selftests/alsa/global-timer.c |  87 ++++++++++
 tools/testing/selftests/alsa/utimer-test.c  | 170 ++++++++++++++++++++
 3 files changed, 258 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/alsa/global-timer.c
 create mode 100644 tools/testing/selftests/alsa/utimer-test.c

diff --git a/tools/testing/selftests/alsa/Makefile b/tools/testing/selftests/alsa/Makefile
index c1ce39874e2b..0d5bd8ea900b 100644
--- a/tools/testing/selftests/alsa/Makefile
+++ b/tools/testing/selftests/alsa/Makefile
@@ -12,7 +12,7 @@ LDLIBS+=-lpthread
 
 OVERRIDE_TARGETS = 1
 
-TEST_GEN_PROGS := mixer-test pcm-test test-pcmtest-driver
+TEST_GEN_PROGS := mixer-test pcm-test utimer-test test-pcmtest-driver global-timer
 
 TEST_GEN_PROGS_EXTENDED := libatest.so
 
diff --git a/tools/testing/selftests/alsa/global-timer.c b/tools/testing/selftests/alsa/global-timer.c
new file mode 100644
index 000000000000..c15ec0ba851a
--- /dev/null
+++ b/tools/testing/selftests/alsa/global-timer.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This tool is used by the utimer test, and it allows us to
+ * count the ticks of a global timer in a certain time frame
+ * (which is set by `timeout` parameter).
+ *
+ * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <alsa/asoundlib.h>
+#include <time.h>
+
+static int ticked;
+static void async_callback(snd_async_handler_t *ahandler)
+{
+	ticked++;
+}
+
+static char timer_name[64];
+static void bind_to_timer(int device, int subdevice, int timeout)
+{
+	snd_timer_t *handle;
+	snd_timer_params_t *params;
+	snd_async_handler_t *ahandler;
+
+	time_t end;
+
+	sprintf(timer_name, "hw:CLASS=%d,SCLASS=%d,DEV=%d,SUBDEV=%d",
+		SND_TIMER_CLASS_GLOBAL, SND_TIMER_SCLASS_NONE,
+		device, subdevice);
+
+	snd_timer_params_alloca(&params);
+
+	if (snd_timer_open(&handle, timer_name, SND_TIMER_OPEN_NONBLOCK) < 0) {
+		perror("Can't open the timer");
+		exit(EXIT_FAILURE);
+	}
+
+	snd_timer_params_set_auto_start(params, 1);
+	snd_timer_params_set_ticks(params, 1);
+	if (snd_timer_params(handle, params) < 0) {
+		perror("Can't set timer params");
+		exit(EXIT_FAILURE);
+	}
+
+	if (snd_async_add_timer_handler(&ahandler, handle, async_callback, NULL) < 0) {
+		perror("Can't create a handler");
+		exit(EXIT_FAILURE);
+	}
+	end = time(NULL) + timeout;
+	if (snd_timer_start(handle) < 0) {
+		perror("Failed to start the timer");
+		exit(EXIT_FAILURE);
+	}
+	printf("Timer has started\n");
+	while (time(NULL) <= end) {
+		/*
+		 * Waiting for the timeout to elapse. Can't use sleep here, as it gets
+		 * constantly interrupted by the signal from the timer (SIGIO)
+		 */
+	}
+	snd_timer_stop(handle);
+	snd_timer_close(handle);
+}
+
+int main(int argc, char *argv[])
+{
+	int device, subdevice, timeout;
+
+	if (argc < 4) {
+		perror("Usage: %s <device> <subdevice> <timeout>");
+		return EXIT_FAILURE;
+	}
+
+	setlinebuf(stdout);
+
+	device = atoi(argv[1]);
+	subdevice = atoi(argv[2]);
+	timeout = atoi(argv[3]);
+
+	bind_to_timer(device, subdevice, timeout);
+
+	printf("Total ticks count: %d\n", ticked);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/testing/selftests/alsa/utimer-test.c b/tools/testing/selftests/alsa/utimer-test.c
new file mode 100644
index 000000000000..fee4d21a1955
--- /dev/null
+++ b/tools/testing/selftests/alsa/utimer-test.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This test covers the functionality of userspace-driven ALSA timers. Such timers
+ * are purely virtual (so they don't directly depend on the hardware), and they could be
+ * created and triggered by userspace applications.
+ *
+ * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
+ */
+#include "../kselftest_harness.h"
+#include <sound/asound.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+
+#define FRAME_RATE 8000
+#define PERIOD_SIZE 4410
+#define UTIMER_DEFAULT_ID -1
+#define NANO 1000000000ULL
+#define TICKS_COUNT 10
+#define TICKS_RECORDING_DELTA 5
+#define TIMER_OUTPUT_BUF_LEN 1024
+#define TIMER_FREQ_SEC 1
+#define RESULT_PREFIX_LEN strlen("Total ticks count: ")
+
+enum timer_app_event {
+	TIMER_APP_STARTED,
+	TIMER_APP_RESULT,
+	TIMER_NO_EVENT,
+};
+
+FIXTURE(timer_f) {
+	int utimer_fd;
+	struct snd_utimer_info *utimer_info;
+};
+
+FIXTURE_SETUP(timer_f) {
+	int timer_dev_fd;
+
+	if (geteuid())
+		SKIP(return, "This test needs root to run!");
+
+	self->utimer_info = calloc(1, sizeof(*self->utimer_info));
+	ASSERT_NE(NULL, self->utimer_info);
+
+	self->utimer_info->frame_rate = FRAME_RATE;
+	self->utimer_info->period_size = PERIOD_SIZE;
+	self->utimer_info->id = UTIMER_DEFAULT_ID;
+
+	timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
+	ASSERT_GE(timer_dev_fd, 0);
+
+	self->utimer_fd = ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, self->utimer_info);
+	ASSERT_GE(self->utimer_fd, 0);
+
+	close(timer_dev_fd);
+}
+
+FIXTURE_TEARDOWN(timer_f) {
+	close(self->utimer_fd);
+	free(self->utimer_info);
+}
+
+static void *ticking_func(void *data)
+{
+	int i;
+	int *fd = (int *)data;
+
+	for (i = 0; i < TICKS_COUNT; i++) {
+		/* Well, trigger the timer! */
+		ioctl(*fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL);
+		sleep(TIMER_FREQ_SEC);
+	}
+
+	return NULL;
+}
+
+static enum timer_app_event parse_timer_output(const char *s)
+{
+	if (strstr(s, "Timer has started"))
+		return TIMER_APP_STARTED;
+	if (strstr(s, "Total ticks count"))
+		return TIMER_APP_RESULT;
+
+	return TIMER_NO_EVENT;
+}
+
+static int parse_timer_result(const char *s)
+{
+	char *end;
+	long d;
+
+	d = strtol(s + RESULT_PREFIX_LEN, &end, 10);
+	if (end == s + RESULT_PREFIX_LEN)
+		return -1;
+
+	return d;
+}
+
+/*
+ * This test triggers the timer and counts ticks at the same time. The amount
+ * of the timer trigger calls should be equal to the amount of ticks received.
+ */
+TEST_F(timer_f, utimer) {
+	char command[64];
+	pthread_t ticking_thread;
+	int total_ticks = 0;
+	FILE *rfp;
+	char *buf = malloc(TIMER_OUTPUT_BUF_LEN);
+
+	ASSERT_NE(buf, NULL);
+
+	/* The timeout should be the ticks interval * count of ticks + some delta */
+	sprintf(command, "./global-timer %d %d %d", SNDRV_TIMER_GLOBAL_UDRIVEN,
+		self->utimer_info->id, TICKS_COUNT * TIMER_FREQ_SEC + TICKS_RECORDING_DELTA);
+
+	rfp = popen(command, "r");
+	while (fgets(buf, TIMER_OUTPUT_BUF_LEN, rfp)) {
+		buf[TIMER_OUTPUT_BUF_LEN - 1] = 0;
+		switch (parse_timer_output(buf)) {
+		case TIMER_APP_STARTED:
+			/* global-timer waits for timer to trigger, so start the ticking thread */
+			pthread_create(&ticking_thread, NULL, ticking_func,
+				       &self->utimer_fd);
+			break;
+		case TIMER_APP_RESULT:
+			total_ticks = parse_timer_result(buf);
+			break;
+		case TIMER_NO_EVENT:
+			break;
+		}
+	}
+	pthread_join(ticking_thread, NULL);
+	ASSERT_EQ(total_ticks, TICKS_COUNT);
+	pclose(rfp);
+}
+
+static struct snd_utimer_info wrong_timers[] = {
+	/* Period size is not valid (=0) */
+	{ .frame_rate = FRAME_RATE, .period_size = 0, .id = UTIMER_DEFAULT_ID },
+	/* Frame rate is not valid (=0) */
+	{ .frame_rate = 0, .period_size = PERIOD_SIZE, .id = UTIMER_DEFAULT_ID },
+	/* Frame rate is too high (which results in resolution = 0) */
+	{ .frame_rate = NANO + 1, .period_size = PERIOD_SIZE, .id = UTIMER_DEFAULT_ID },
+	/* Causes overflow in resolution */
+	{ .frame_rate = 1, .period_size = ULONG_MAX / NANO + 1, .id = UTIMER_DEFAULT_ID },
+};
+
+TEST(wrong_timers_test) {
+	int timer_dev_fd;
+	int utimer_id;
+	size_t i;
+
+	timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
+	ASSERT_GE(timer_dev_fd, 0);
+
+	for (i = 0; i < ARRAY_SIZE(wrong_timers); i++) {
+		utimer_id = ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, &wrong_timers[i]);
+		ASSERT_LT(utimer_id, 0);
+		/* Check that id was not updated */
+		ASSERT_EQ(wrong_timers[i].id, UTIMER_DEFAULT_ID);
+	}
+
+	close(timer_dev_fd);
+}
+
+TEST_HARNESS_MAIN
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test
  2024-08-06 12:52 ` [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test Ivan Orlov
@ 2024-08-06 13:04   ` Mark Brown
  2024-08-06 13:53     ` Ivan Orlov
  0 siblings, 1 reply; 10+ messages in thread
From: Mark Brown @ 2024-08-06 13:04 UTC (permalink / raw)
  To: Ivan Orlov
  Cc: perex, tiwai, corbet, shuah, linux-kselftest, linux-doc,
	linux-sound, linux-kernel, christophe.jaillet, aholzinger

[-- Attachment #1: Type: text/plain, Size: 979 bytes --]

On Tue, Aug 06, 2024 at 01:52:43PM +0100, Ivan Orlov wrote:

> -TEST_GEN_PROGS := mixer-test pcm-test test-pcmtest-driver
> +TEST_GEN_PROGS := mixer-test pcm-test utimer-test test-pcmtest-driver global-timer

This is adding the timer timer tests as standard kselftests to be run by
the wrapper script...

> index 000000000000..c15ec0ba851a
> --- /dev/null
> +++ b/tools/testing/selftests/alsa/global-timer.c

> +int main(int argc, char *argv[])
> +{
> +	int device, subdevice, timeout;
> +
> +	if (argc < 4) {
> +		perror("Usage: %s <device> <subdevice> <timeout>");
> +		return EXIT_FAILURE;
> +	}

...but this requires specific arguments to be run which the kselftest
runner won't supply.  I'd expect it to be a good default to enumerate
and test every possible device and generate a test for each.  However it
looks like this is really intended not as a standalone test but rather
as something run from within utimer-test, in that case it should be a
TEST_GEN_PROGS_EXTENDED.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers
  2024-08-06 12:52 ` [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers Ivan Orlov
@ 2024-08-06 13:11   ` Jaroslav Kysela
  2024-08-06 13:56     ` Ivan Orlov
  2024-08-08  9:22   ` kernel test robot
  1 sibling, 1 reply; 10+ messages in thread
From: Jaroslav Kysela @ 2024-08-06 13:11 UTC (permalink / raw)
  To: Ivan Orlov, tiwai, corbet, broonie, shuah
  Cc: linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

On 06. 08. 24 14:52, Ivan Orlov wrote:
> Implement two ioctl calls in order to support virtual userspace-driven
> ALSA timers.

...

> +struct snd_utimer_info {
> +	/*
> +	 * To pretend being a normal timer, we need to know the frame rate and
> +	 * the period size in frames.
> +	 */
> +	__u64 frame_rate;
> +	__u64 period_size;

There should be just one timer resolution in ns member (like in struct 
snd_timer_ginfo - not frame/period members here - it's too specific). The 
resolution can be calculated in the user space from the rate and period size.

Also naming - the timer API uses snd_timer prefix for structures, thus 
snd_timer_uinfo should be more appropriate.

					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test
  2024-08-06 13:04   ` Mark Brown
@ 2024-08-06 13:53     ` Ivan Orlov
  0 siblings, 0 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 13:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: perex, tiwai, corbet, shuah, linux-kselftest, linux-doc,
	linux-sound, linux-kernel, christophe.jaillet, aholzinger

On 8/6/24 14:04, Mark Brown wrote:
> On Tue, Aug 06, 2024 at 01:52:43PM +0100, Ivan Orlov wrote:
> 
>> -TEST_GEN_PROGS := mixer-test pcm-test test-pcmtest-driver
>> +TEST_GEN_PROGS := mixer-test pcm-test utimer-test test-pcmtest-driver global-timer
> 
> This is adding the timer timer tests as standard kselftests to be run by
> the wrapper script...
> 
>> index 000000000000..c15ec0ba851a
>> --- /dev/null
>> +++ b/tools/testing/selftests/alsa/global-timer.c
> 
>> +int main(int argc, char *argv[])
>> +{
>> +	int device, subdevice, timeout;
>> +
>> +	if (argc < 4) {
>> +		perror("Usage: %s <device> <subdevice> <timeout>");
>> +		return EXIT_FAILURE;
>> +	}
> 
> ...but this requires specific arguments to be run which the kselftest
> runner won't supply.  I'd expect it to be a good default to enumerate
> and test every possible device and generate a test for each.  However it
> looks like this is really intended not as a standalone test but rather
> as something run from within utimer-test, in that case it should be a
> TEST_GEN_PROGS_EXTENDED.

Hi Mark,

Yes, the 'global-timer' application is not a standalone test and it 
should be ran by 'utimer-test'. I had to extract the timer-binding 
functionality into a different application as we can't have 
'sound/asound.h' and 'alsa/asoundlib.h' in single source due to some 
declarations overlap problems.

I'll move the 'global-timer' tool into the TEST_GEN_PROGS_EXTENDED list.

Thank you so much for the review!

-- 
Kind regards,
Ivan Orlov

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers
  2024-08-06 13:11   ` Jaroslav Kysela
@ 2024-08-06 13:56     ` Ivan Orlov
  0 siblings, 0 replies; 10+ messages in thread
From: Ivan Orlov @ 2024-08-06 13:56 UTC (permalink / raw)
  To: Jaroslav Kysela, tiwai, corbet, broonie, shuah
  Cc: linux-kselftest, linux-doc, linux-sound, linux-kernel,
	christophe.jaillet, aholzinger

On 8/6/24 14:11, Jaroslav Kysela wrote:
> On 06. 08. 24 14:52, Ivan Orlov wrote:
>> Implement two ioctl calls in order to support virtual userspace-driven
>> ALSA timers.
> 
> ...
> 

Hi Jaroslav,

>> +struct snd_utimer_info {
>> +    /*
>> +     * To pretend being a normal timer, we need to know the frame 
>> rate and
>> +     * the period size in frames.
>> +     */
>> +    __u64 frame_rate;
>> +    __u64 period_size;
> 
> There should be just one timer resolution in ns member (like in struct 
> snd_timer_ginfo - not frame/period members here - it's too specific). 
> The resolution can be calculated in the user space from the rate and 
> period size.
> 

Ah, yes, I agree... Also, it should help us to avoid complex 
calculations and sanity checks in the kernel space. I'll replace these 
two fields with 'resolution' field in V4, thanks!

> Also naming - the timer API uses snd_timer prefix for structures, thus 
> snd_timer_uinfo should be more appropriate.
> 
Alright, I'll rename the structure.

Thank you so much for the review!

-- 
Kind regards,
Ivan Orlov

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers
  2024-08-06 12:52 ` [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers Ivan Orlov
  2024-08-06 13:11   ` Jaroslav Kysela
@ 2024-08-08  9:22   ` kernel test robot
  1 sibling, 0 replies; 10+ messages in thread
From: kernel test robot @ 2024-08-08  9:22 UTC (permalink / raw)
  To: Ivan Orlov, perex, tiwai, corbet, broonie, shuah
  Cc: oe-kbuild-all, Ivan Orlov, linux-kselftest, linux-doc,
	linux-sound, linux-kernel, christophe.jaillet, aholzinger

Hi Ivan,

kernel test robot noticed the following build errors:

[auto build test ERROR on tiwai-sound/for-next]
[also build test ERROR on tiwai-sound/for-linus linus/master v6.11-rc2 next-20240808]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ivan-Orlov/ALSA-aloop-Allow-using-global-timers/20240806-210332
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
patch link:    https://lore.kernel.org/r/20240806125243.449959-4-ivan.orlov0322%40gmail.com
patch subject: [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers
config: arm-randconfig-r064-20240807 (https://download.01.org/0day-ci/archive/20240808/202408081612.hvfwzVlB-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240808/202408081612.hvfwzVlB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408081612.hvfwzVlB-lkp@intel.com/

All errors (new ones prefixed by >>):

   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_submit_wmt_recv_urb':
   drivers/bluetooth/btmtk.c:531:(.text+0x6c2): undefined reference to `usb_alloc_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:537:(.text+0x6e6): undefined reference to `usb_free_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:561:(.text+0x750): undefined reference to `usb_anchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:562:(.text+0x75a): undefined reference to `usb_submit_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:567:(.text+0x796): undefined reference to `usb_unanchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:570:(.text+0x7a0): undefined reference to `usb_free_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_submit_intr_urb':
   drivers/bluetooth/btmtk.c:1174:(.text+0x80e): undefined reference to `usb_alloc_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1181:(.text+0x83a): undefined reference to `usb_free_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1195:(.text+0x8c4): undefined reference to `usb_anchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1197:(.text+0x8cc): undefined reference to `usb_submit_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1202:(.text+0x908): undefined reference to `usb_unanchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1205:(.text+0x912): undefined reference to `usb_free_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_suspend':
   drivers/bluetooth/btmtk.c:1265:(.text+0x988): undefined reference to `usb_kill_anchored_urbs'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_intr_complete':
   drivers/bluetooth/btmtk.c:1145:(.text+0xbf2): undefined reference to `usb_anchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1147:(.text+0xbfc): undefined reference to `usb_submit_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:1157:(.text+0xc48): undefined reference to `usb_unanchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `__set_mtk_intr_interface':
   drivers/bluetooth/btmtk.c:991:(.text+0xcf4): undefined reference to `usb_set_interface'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_isointf_init':
   drivers/bluetooth/btmtk.c:1224:(.text+0xd30): undefined reference to `usb_kill_anchored_urbs'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_hci_wmt_sync':
   drivers/bluetooth/btmtk.c:610:(.text+0xf26): undefined reference to `usb_autopm_get_interface'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:618:(.text+0xf54): undefined reference to `usb_autopm_put_interface'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:625:(.text+0xf7e): undefined reference to `usb_autopm_put_interface'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_reg_read':
   drivers/bluetooth/btmtk.c:790:(.text+0x1248): undefined reference to `usb_control_msg'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_uhw_reg_write':
   drivers/bluetooth/btmtk.c:738:(.text+0x12e0): undefined reference to `usb_control_msg'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_uhw_reg_read':
   drivers/bluetooth/btmtk.c:761:(.text+0x1374): undefined reference to `usb_control_msg'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_recv_acl':
   drivers/bluetooth/btmtk.c:946:(.text+0x1e06): undefined reference to `usb_disable_autosuspend'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_wmt_recv':
   drivers/bluetooth/btmtk.c:508:(.text+0x1e72): undefined reference to `usb_anchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:509:(.text+0x1e7c): undefined reference to `usb_submit_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.c:518:(.text+0x1ec0): undefined reference to `usb_unanchor_urb'
   arm-linux-gnueabi-ld: drivers/bluetooth/btmtk.o: in function `alloc_mtk_intr_urb':
   drivers/bluetooth/btmtk.c:1037:(.text+0x1fc8): undefined reference to `usb_alloc_urb'
   arm-linux-gnueabi-ld: sound/core/timer.o: in function `snd_utimer_create':
>> sound/core/timer.c:2127:(.text+0x255c): undefined reference to `__aeabi_uldivmod'


vim +2127 sound/core/timer.c

  2112	
  2113	static int snd_utimer_create(struct snd_utimer_info *utimer_info,
  2114				     struct snd_utimer **r_utimer)
  2115	{
  2116		struct snd_utimer *utimer;
  2117		struct snd_timer *timer;
  2118		struct snd_timer_id tid;
  2119		int utimer_id;
  2120		int err = 0;
  2121		u64 resolution;
  2122	
  2123		if (!utimer_info || utimer_info->frame_rate == 0 || utimer_info->period_size == 0)
  2124			return -EINVAL;
  2125	
  2126		/* Let's check that we won't get an overflow in the resolution */
> 2127		if (NANO / utimer_info->frame_rate > U64_MAX / utimer_info->period_size)
  2128			return -EINVAL;
  2129	
  2130		resolution = NANO / utimer_info->frame_rate * utimer_info->period_size;
  2131	
  2132		if (resolution == 0)
  2133			return -EINVAL;
  2134	
  2135		utimer = kzalloc(sizeof(*utimer), GFP_KERNEL);
  2136		if (!utimer)
  2137			return -ENOMEM;
  2138	
  2139		/* We hold the ioctl lock here so we won't get a race condition when allocating id */
  2140		utimer_id = snd_utimer_take_id();
  2141		if (utimer_id < 0) {
  2142			err = utimer_id;
  2143			goto err_take_id;
  2144		}
  2145	
  2146		utimer->name = kasprintf(GFP_KERNEL, "snd-utimer%d", utimer_id);
  2147		if (!utimer->name) {
  2148			err = -ENOMEM;
  2149			goto err_get_name;
  2150		}
  2151	
  2152		utimer->id = utimer_id;
  2153	
  2154		tid.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
  2155		tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
  2156		tid.card = -1;
  2157		tid.device = SNDRV_TIMER_GLOBAL_UDRIVEN;
  2158		tid.subdevice = utimer_id;
  2159	
  2160		err = snd_timer_new(NULL, utimer->name, &tid, &timer);
  2161		if (err < 0) {
  2162			pr_err("Can't create userspace-driven timer\n");
  2163			goto err_timer_new;
  2164		}
  2165	
  2166		timer->module = THIS_MODULE;
  2167		timer->hw = timer_hw;
  2168		timer->hw.resolution = resolution;
  2169		timer->hw.ticks = 1;
  2170		timer->max_instances = MAX_SLAVE_INSTANCES;
  2171	
  2172		utimer->timer = timer;
  2173	
  2174		err = snd_timer_global_register(timer);
  2175		if (err < 0) {
  2176			pr_err("Can't register a userspace-driven timer\n");
  2177			goto err_timer_reg;
  2178		}
  2179	
  2180		*r_utimer = utimer;
  2181		return 0;
  2182	
  2183	err_timer_reg:
  2184		snd_timer_free(timer);
  2185	err_timer_new:
  2186		kfree(utimer->name);
  2187	err_get_name:
  2188		snd_utimer_put_id(utimer);
  2189	err_take_id:
  2190		kfree(utimer);
  2191	
  2192		return err;
  2193	}
  2194	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2024-08-08  9:24 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-06 12:52 [PATCH v3 0/4] Introduce userspace-driven ALSA timers Ivan Orlov
2024-08-06 12:52 ` [PATCH v3 1/4] ALSA: aloop: Allow using global timers Ivan Orlov
2024-08-06 12:52 ` [PATCH v3 2/4] Docs/sound: Add documentation for userspace-driven ALSA timers Ivan Orlov
2024-08-06 12:52 ` [PATCH v3 3/4] ALSA: timer: Introduce virtual userspace-driven timers Ivan Orlov
2024-08-06 13:11   ` Jaroslav Kysela
2024-08-06 13:56     ` Ivan Orlov
2024-08-08  9:22   ` kernel test robot
2024-08-06 12:52 ` [PATCH v3 4/4] selftests: ALSA: Cover userspace-driven timers with test Ivan Orlov
2024-08-06 13:04   ` Mark Brown
2024-08-06 13:53     ` Ivan Orlov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).