All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: alsa-devel@alsa-project.org
Cc: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH 01/24] ALSA: pcm: Add copy ops with universal sockptr_t
Date: Mon, 31 Jul 2023 17:46:55 +0200	[thread overview]
Message-ID: <20230731154718.31048-2-tiwai@suse.de> (raw)
In-Reply-To: <20230731154718.31048-1-tiwai@suse.de>

sockptr is a universal pointer that can represent both kernel- and
user-space pointers.  Despite of its name, sockptr is already widely
used in quite a few subsystems as a generic solution, and it fits
pretty well for ALSA PCM copy ops, too; we had to split to copy_user
and copy_kernel, and those can be unified to a single ops with
sockptr_t.

So here it is: this patch adds a new PCM copy ops that passes
sockptr_t pointer for copying both kernel and user-space more
consistently.  This patch touches only the ALSA PCM core part, and the
actual users will be replaced in the following patches.

As of now, the old copy_user and copy_kernel ops are still kept.
Once after all users are converted, we'll drop the old copy_user and
copy_kernel ops, too.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/pcm.h     |  3 ++
 sound/core/pcm_lib.c    | 97 ++++++++++++++++++++++-------------------
 sound/core/pcm_native.c |  2 +-
 3 files changed, 57 insertions(+), 45 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 19f564606ac4..04b935200d0e 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -16,6 +16,7 @@
 #include <linux/bitops.h>
 #include <linux/pm_qos.h>
 #include <linux/refcount.h>
+#include <linux/sockptr.h>
 
 #define snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_chip(pcm) ((pcm)->private_data)
@@ -68,6 +69,8 @@ struct snd_pcm_ops {
 			struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
 	int (*fill_silence)(struct snd_pcm_substream *substream, int channel,
 			    unsigned long pos, unsigned long bytes);
+	int (*copy)(struct snd_pcm_substream *substream, int channel,
+		    unsigned long pos, sockptr_t buf, unsigned long bytes);
 	int (*copy_user)(struct snd_pcm_substream *substream, int channel,
 			 unsigned long pos, void __user *buf,
 			 unsigned long bytes);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 9c121a921b04..1dd630cd22a7 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1973,10 +1973,11 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
 	
 typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream,
 			      int channel, unsigned long hwoff,
-			      void *buf, unsigned long bytes);
+			      sockptr_t buf, unsigned long bytes);
 
 typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *,
-			  snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f);
+			  snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f,
+			  bool);
 
 /* calculate the target DMA-buffer position to be written/read */
 static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
@@ -1986,32 +1987,23 @@ static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
 		channel * (runtime->dma_bytes / runtime->channels);
 }
 
-/* default copy_user ops for write; used for both interleaved and non- modes */
+/* default copy ops for write; used for both interleaved and non- modes */
 static int default_write_copy(struct snd_pcm_substream *substream,
 			      int channel, unsigned long hwoff,
-			      void *buf, unsigned long bytes)
+			      sockptr_t buf, unsigned long bytes)
 {
-	if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff),
-			   (void __user *)buf, bytes))
+	if (copy_from_sockptr(get_dma_ptr(substream->runtime, channel, hwoff),
+			      buf, bytes))
 		return -EFAULT;
 	return 0;
 }
 
-/* default copy_kernel ops for write */
-static int default_write_copy_kernel(struct snd_pcm_substream *substream,
-				     int channel, unsigned long hwoff,
-				     void *buf, unsigned long bytes)
-{
-	memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes);
-	return 0;
-}
-
 /* fill silence instead of copy data; called as a transfer helper
  * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when
  * a NULL buffer is passed
  */
 static int fill_silence(struct snd_pcm_substream *substream, int channel,
-			unsigned long hwoff, void *buf, unsigned long bytes)
+			unsigned long hwoff, sockptr_t buf, unsigned long bytes)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
@@ -2027,27 +2019,42 @@ static int fill_silence(struct snd_pcm_substream *substream, int channel,
 	return 0;
 }
 
-/* default copy_user ops for read; used for both interleaved and non- modes */
+/* default copy ops for read; used for both interleaved and non- modes */
 static int default_read_copy(struct snd_pcm_substream *substream,
 			     int channel, unsigned long hwoff,
-			     void *buf, unsigned long bytes)
+			     sockptr_t buf, unsigned long bytes)
 {
-	if (copy_to_user((void __user *)buf,
-			 get_dma_ptr(substream->runtime, channel, hwoff),
-			 bytes))
+	if (copy_to_sockptr(buf,
+			    get_dma_ptr(substream->runtime, channel, hwoff),
+			    bytes))
 		return -EFAULT;
 	return 0;
 }
 
-/* default copy_kernel ops for read */
-static int default_read_copy_kernel(struct snd_pcm_substream *substream,
-				    int channel, unsigned long hwoff,
-				    void *buf, unsigned long bytes)
+/* a wrapper for calling old copy_kernel or copy_user ops */
+static int call_old_copy(struct snd_pcm_substream *substream,
+			 int channel, unsigned long hwoff,
+			 sockptr_t buf, unsigned long bytes)
 {
-	memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes);
-	return 0;
+	if (sockptr_is_kernel(buf))
+		return substream->ops->copy_kernel(substream, channel, hwoff,
+						   buf.kernel, bytes);
+	else
+		return substream->ops->copy_user(substream, channel, hwoff,
+						 buf.user, bytes);
 }
 
+/* create a sockptr_t */
+static inline sockptr_t make_sockptr(void *p, bool in_kernel)
+{
+	if (in_kernel)
+		return KERNEL_SOCKPTR(p);
+	else
+		return USER_SOCKPTR((void __user *)p);
+}
+
+#define NULL_SOCKPTR	USER_SOCKPTR(NULL)
+
 /* call transfer function with the converted pointers and sizes;
  * for interleaved mode, it's one shot for all samples
  */
@@ -2055,7 +2062,8 @@ static int interleaved_copy(struct snd_pcm_substream *substream,
 			    snd_pcm_uframes_t hwoff, void *data,
 			    snd_pcm_uframes_t off,
 			    snd_pcm_uframes_t frames,
-			    pcm_transfer_f transfer)
+			    pcm_transfer_f transfer,
+			    bool in_kernel)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
@@ -2063,7 +2071,8 @@ static int interleaved_copy(struct snd_pcm_substream *substream,
 	hwoff = frames_to_bytes(runtime, hwoff);
 	off = frames_to_bytes(runtime, off);
 	frames = frames_to_bytes(runtime, frames);
-	return transfer(substream, 0, hwoff, data + off, frames);
+	return transfer(substream, 0, hwoff,
+			make_sockptr(data + off, in_kernel), frames);
 }
 
 /* call transfer function with the converted pointers and sizes for each
@@ -2073,7 +2082,8 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream,
 			       snd_pcm_uframes_t hwoff, void *data,
 			       snd_pcm_uframes_t off,
 			       snd_pcm_uframes_t frames,
-			       pcm_transfer_f transfer)
+			       pcm_transfer_f transfer,
+			       bool in_kernel)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int channels = runtime->channels;
@@ -2089,9 +2099,11 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream,
 	hwoff = samples_to_bytes(runtime, hwoff);
 	for (c = 0; c < channels; ++c, ++bufs) {
 		if (!data || !*bufs)
-			err = fill_silence(substream, c, hwoff, NULL, frames);
+			err = fill_silence(substream, c, hwoff,
+					   NULL_SOCKPTR, frames);
 		else
-			err = transfer(substream, c, hwoff, *bufs + off,
+			err = transfer(substream, c, hwoff,
+				       make_sockptr(*bufs + off, in_kernel),
 				       frames);
 		if (err < 0)
 			return err;
@@ -2108,10 +2120,10 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
 	if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
 	    substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED)
 		return interleaved_copy(substream, off, NULL, 0, frames,
-					fill_silence);
+					fill_silence, true);
 	else
 		return noninterleaved_copy(substream, off, NULL, 0, frames,
-					   fill_silence);
+					   fill_silence, true);
 }
 
 /* sanity-check for read/write methods */
@@ -2121,7 +2133,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 	runtime = substream->runtime;
-	if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))
+	if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
 		return -EINVAL;
 	if (runtime->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
@@ -2226,15 +2238,12 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
 			transfer = fill_silence;
 		else
 			return -EINVAL;
-	} else if (in_kernel) {
-		if (substream->ops->copy_kernel)
-			transfer = substream->ops->copy_kernel;
-		else
-			transfer = is_playback ?
-				default_write_copy_kernel : default_read_copy_kernel;
 	} else {
-		if (substream->ops->copy_user)
-			transfer = (pcm_transfer_f)substream->ops->copy_user;
+		if (substream->ops->copy)
+			transfer = substream->ops->copy;
+		else if ((in_kernel && substream->ops->copy_kernel) ||
+			 (!in_kernel && substream->ops->copy_user))
+			transfer = call_old_copy;
 		else
 			transfer = is_playback ?
 				default_write_copy : default_read_copy;
@@ -2307,7 +2316,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
 		if (!is_playback)
 			snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
 		err = writer(substream, appl_ofs, data, offset, frames,
-			     transfer);
+			     transfer, in_kernel);
 		if (is_playback)
 			snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
 		snd_pcm_stream_lock_irq(substream);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 95fc56e403b1..34efd4d198d6 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -809,7 +809,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 		runtime->boundary *= 2;
 
 	/* clear the buffer for avoiding possible kernel info leaks */
-	if (runtime->dma_area && !substream->ops->copy_user) {
+	if (runtime->dma_area && !substream->ops->copy && !substream->ops->copy_user) {
 		size_t size = runtime->dma_bytes;
 
 		if (runtime->info & SNDRV_PCM_INFO_MMAP)
-- 
2.35.3


  reply	other threads:[~2023-07-31 15:49 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-31 15:46 [PATCH 00/24] ALSA: Generic PCM copy ops using sockptr_t Takashi Iwai
2023-07-31 15:46 ` Takashi Iwai [this message]
2023-07-31 15:46 ` [PATCH 02/24] ALSA: core: Add memory copy helpers between sockptr and iomem Takashi Iwai
2023-07-31 15:46 ` [PATCH 03/24] ALSA: dummy: Convert to generic PCM copy ops Takashi Iwai
2023-07-31 15:46 ` [PATCH 04/24] ALSA: gus: " Takashi Iwai
2023-07-31 15:46 ` [PATCH 05/24] ALSA: emu8000: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 06/24] ALSA: es1938: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 07/24] ALSA: korg1212: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 08/24] ALSA: nm256: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 09/24] ALSA: rme32: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 10/24] ALSA: rme96: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 11/24] ALSA: hdsp: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 12/24] ALSA: rme9652: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 13/24] ALSA: sh: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 14/24] ALSA: xen: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 15/24] ALSA: pcmtest: Update comment about " Takashi Iwai
2023-07-31 15:47 ` [PATCH 16/24] media: solo6x10: Convert to generic " Takashi Iwai
2023-07-31 15:47 ` [PATCH 17/24] ASoC: component: Add " Takashi Iwai
2023-07-31 15:47 ` [PATCH 18/24] ASoC: mediatek: Convert to " Takashi Iwai
2023-07-31 15:47 ` [PATCH 19/24] ASoC: qcom: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 20/24] ASoC: dmaengine: " Takashi Iwai
2023-07-31 15:47 ` [PATCH 21/24] ASoC: dmaengine: Use sockptr_t for process callback, too Takashi Iwai
2023-07-31 15:47 ` [PATCH 22/24] ALSA: doc: Update description for the new PCM copy ops Takashi Iwai
2023-07-31 15:47 ` [PATCH 23/24] ASoC: pcm: Drop obsoleted PCM copy_user ops Takashi Iwai
2023-07-31 15:47 ` [PATCH 24/24] ALSA: pcm: Drop obsoleted PCM copy_user and copy_kernel ops Takashi Iwai
2023-07-31 17:20 ` [PATCH 00/24] ALSA: Generic PCM copy ops using sockptr_t Mark Brown
2023-07-31 19:30   ` Takashi Iwai
2023-07-31 19:40     ` Mark Brown
2023-08-01 12:54       ` Takashi Iwai
2023-08-01 14:04         ` Mark Brown
2023-08-01 17:51         ` Andy Shevchenko
2023-08-07 15:22           ` Takashi Iwai
2023-08-07 16:00             ` Andy Shevchenko
2023-08-01 13:57     ` Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230731154718.31048-2-tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@alsa-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.