[3/3] ALSA: pcm: conditionally avoid mmap of control data
diff mbox

Message ID 1494896518-23399-4-git-send-email-subhransu.s.prusty@intel.com
State New
Headers show

Commit Message

Subhransu S. Prusty May 16, 2017, 1:01 a.m. UTC
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>

In case of mmap, by default alsa-lib mmaps both control and status data.

If driver subscribes for application pointer update, driver needs to get
notification whenever appl ptr changes. With the above case driver won't
get appl ptr notifications.

This patch check on a hw info flag and returns error when user land asks
for mmaping control & status data, thus forcing user to issue
IOCTL_SYNC_PTR.

Suggested-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Ramesh Babu <ramesh.babu@intel.com>
Signed-off-by: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
---
 include/uapi/sound/asound.h |  1 +
 sound/core/pcm_native.c     | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

Comments

Takashi Sakamoto May 16, 2017, 5:38 a.m. UTC | #1
Hi,

On May 16 2017 10:01, Subhransu S. Prusty wrote:
> From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
>
> In case of mmap, by default alsa-lib mmaps both control and status data.
>
> If driver subscribes for application pointer update, driver needs to get
> notification whenever appl ptr changes. With the above case driver won't
> get appl ptr notifications.
>
> This patch check on a hw info flag and returns error when user land asks
> for mmaping control & status data, thus forcing user to issue
> IOCTL_SYNC_PTR.
>
> Suggested-by: Takashi Iwai <tiwai@suse.de>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Signed-off-by: Ramesh Babu <ramesh.babu@intel.com>
> Signed-off-by: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
> Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
> ---
>  include/uapi/sound/asound.h |  1 +
>  sound/core/pcm_native.c     | 17 +++++++++++++++++
>  2 files changed, 18 insertions(+)

Would you please explain about the case that drivers can't support page 
frame mapping, please?

As long as I know, it depends on kernel and platform architecture 
whether mapping is available or not, because the data of 'struct 
snd_pcm_mmap_status' and 'struct snd_pcm_mmap_control' is not directly 
related to data transmission and independent of target device design.

Of course, I can understand your intension for previous patches. But the 
code comment is quite misleading and worthless.

> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> index c697ff90450d..dea7d89b41ca 100644
> --- a/include/uapi/sound/asound.h
> +++ b/include/uapi/sound/asound.h
> @@ -284,6 +284,7 @@ enum {
>  #define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
>  #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
>  #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
> +#define SNDRV_PCM_INFO_NO_STATUS_MMAP	0x10000000	/* status and control mmap not supported */
>
>  #define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
>  #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index c14cdbd9ff86..2635a7d4d1fa 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -3524,21 +3524,38 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
>  	struct snd_pcm_file * pcm_file;
>  	struct snd_pcm_substream *substream;	
>  	unsigned long offset;
> +	unsigned int info;
>  	
>  	pcm_file = file->private_data;
>  	substream = pcm_file->substream;
>  	if (PCM_RUNTIME_CHECK(substream))
>  		return -ENXIO;
> +	info = substream->runtime->hw.info;
>
>  	offset = area->vm_pgoff << PAGE_SHIFT;
>  	switch (offset) {
>  	case SNDRV_PCM_MMAP_OFFSET_STATUS:
>  		if (pcm_file->no_compat_mmap)
>  			return -ENXIO;
> +		/*
> +		 * force fallback to ioctl if driver doesn't support status
> +		 * and control mmap.
> +		 */
> +		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
> +			return -ENXIO;
> +
>  		return snd_pcm_mmap_status(substream, file, area);
>  	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
>  		if (pcm_file->no_compat_mmap)
>  			return -ENXIO;
> +
> +		/*
> +		 * force fallback to ioctl if driver doesn't support status
> +		 * and control mmap.
> +		 */
> +		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
> +			return -ENXIO;
> +
>  		return snd_pcm_mmap_control(substream, file, area);
>  	default:
>  		return snd_pcm_mmap_data(substream, file, area);

Regards

Takashi Sakamoto
Takashi Iwai May 16, 2017, 5:46 a.m. UTC | #2
On Tue, 16 May 2017 07:38:40 +0200,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> On May 16 2017 10:01, Subhransu S. Prusty wrote:
> > From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> >
> > In case of mmap, by default alsa-lib mmaps both control and status data.
> >
> > If driver subscribes for application pointer update, driver needs to get
> > notification whenever appl ptr changes. With the above case driver won't
> > get appl ptr notifications.
> >
> > This patch check on a hw info flag and returns error when user land asks
> > for mmaping control & status data, thus forcing user to issue
> > IOCTL_SYNC_PTR.
> >
> > Suggested-by: Takashi Iwai <tiwai@suse.de>
> > Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> > Signed-off-by: Ramesh Babu <ramesh.babu@intel.com>
> > Signed-off-by: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
> > Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
> > ---
> >  include/uapi/sound/asound.h |  1 +
> >  sound/core/pcm_native.c     | 17 +++++++++++++++++
> >  2 files changed, 18 insertions(+)
> 
> Would you please explain about the case that drivers can't support
> page frame mapping, please?
> 
> As long as I know, it depends on kernel and platform architecture
> whether mapping is available or not, because the data of 'struct
> snd_pcm_mmap_status' and 'struct snd_pcm_mmap_control' is not directly
> related to data transmission and independent of target device design.

It's only a part of the condition.

In this case, the problem is that the mmap control allows the appl_ptr
being changed silently without interaction with the driver.  If the
driver requires some explicit action for changing the appl_ptr, it
won't work.

> Of course, I can understand your intension for previous patches. But
> the code comment is quite misleading and worthless.

Worthless is a too strong word, but I agree that more clarification
would be more helpful.


thanks,

Takashi

> 
> > diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> > index c697ff90450d..dea7d89b41ca 100644
> > --- a/include/uapi/sound/asound.h
> > +++ b/include/uapi/sound/asound.h
> > @@ -284,6 +284,7 @@ enum {
> >  #define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
> >  #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
> >  #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
> > +#define SNDRV_PCM_INFO_NO_STATUS_MMAP	0x10000000	/* status and control mmap not supported */
> >
> >  #define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
> >  #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
> > diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> > index c14cdbd9ff86..2635a7d4d1fa 100644
> > --- a/sound/core/pcm_native.c
> > +++ b/sound/core/pcm_native.c
> > @@ -3524,21 +3524,38 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
> >  	struct snd_pcm_file * pcm_file;
> >  	struct snd_pcm_substream *substream;	
> >  	unsigned long offset;
> > +	unsigned int info;
> >  	
> >  	pcm_file = file->private_data;
> >  	substream = pcm_file->substream;
> >  	if (PCM_RUNTIME_CHECK(substream))
> >  		return -ENXIO;
> > +	info = substream->runtime->hw.info;
> >
> >  	offset = area->vm_pgoff << PAGE_SHIFT;
> >  	switch (offset) {
> >  	case SNDRV_PCM_MMAP_OFFSET_STATUS:
> >  		if (pcm_file->no_compat_mmap)
> >  			return -ENXIO;
> > +		/*
> > +		 * force fallback to ioctl if driver doesn't support status
> > +		 * and control mmap.
> > +		 */
> > +		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
> > +			return -ENXIO;
> > +
> >  		return snd_pcm_mmap_status(substream, file, area);
> >  	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
> >  		if (pcm_file->no_compat_mmap)
> >  			return -ENXIO;
> > +
> > +		/*
> > +		 * force fallback to ioctl if driver doesn't support status
> > +		 * and control mmap.
> > +		 */
> > +		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
> > +			return -ENXIO;
> > +
> >  		return snd_pcm_mmap_control(substream, file, area);
> >  	default:
> >  		return snd_pcm_mmap_data(substream, file, area);
> 
> Regards
> 
> Takashi Sakamoto
>
Takashi Sakamoto May 16, 2017, 5:57 a.m. UTC | #3
On May 16 2017 14:46, Takashi Iwai wrote:
> In this case, the problem is that the mmap control allows the appl_ptr
> being changed silently without interaction with the driver.  If the
> driver requires some explicit action for changing the appl_ptr, it
> won't work.

I think 'struct snd_pcm_ops.pointer' is available for this purpose, too.

static snd_pcm_sframes_t snd_pcm_playback_rewind(...)
{
     ...
     hw_avail = snd_pcm_playback_hw_avail(runtime);
     (->struct snd_pcm_ops.pointer())
     ...
     (rewind PCM frames)
     ...
+   substream->ops->pointer(...);
     (->struct snd_pcm_ops.pointer())
     ...
}

If drivers need to handle event to update the appl_ptr, it records value 
of the appl_ptr, then compare it to current value to get the updates.

I note that the callback is done in both of process/irq contexts.

On May 16 2017 14:46, Takashi Iwai wrote:
 > Worthless is a too strong word, but I agree that more clarification
 > would be more helpful.

Sorry to use such strong expression. I'll care of it.


Regards

Takashi Sakamoto
Takashi Iwai May 16, 2017, 6:18 a.m. UTC | #4
On Tue, 16 May 2017 07:57:30 +0200,
Takashi Sakamoto wrote:
> 
> On May 16 2017 14:46, Takashi Iwai wrote:
> > In this case, the problem is that the mmap control allows the appl_ptr
> > being changed silently without interaction with the driver.  If the
> > driver requires some explicit action for changing the appl_ptr, it
> > won't work.
> 
> I think 'struct snd_pcm_ops.pointer' is available for this purpose, too.
> 
> static snd_pcm_sframes_t snd_pcm_playback_rewind(...)
> {
>     ...
>     hw_avail = snd_pcm_playback_hw_avail(runtime);
>     (->struct snd_pcm_ops.pointer())
>     ...
>     (rewind PCM frames)
>     ...
> +   substream->ops->pointer(...);
>     (->struct snd_pcm_ops.pointer())
>     ...
> }
> 
> If drivers need to handle event to update the appl_ptr, it records
> value of the appl_ptr, then compare it to current value to get the
> updates.

IIRC, the problem isn't about the forward / rewind but about the
normal data transfer.  In mmap mode, we transfer data on the mmap
buffer, and update appl_ptr via mmap control.  Both are done without
notification to the driver (which is intentional for avoiding the
context switching).

So we want to disable this optimization and always notify to the
driver.  Disabling mmap status/control is the straight hack as it
falls back to ioctl and then the driver can know the change.


Takashi
Takashi Sakamoto May 16, 2017, 6:24 a.m. UTC | #5
On May 16 2017 15:18, Takashi Iwai wrote:
> On Tue, 16 May 2017 07:57:30 +0200,
> Takashi Sakamoto wrote:
>>
>> On May 16 2017 14:46, Takashi Iwai wrote:
>>> In this case, the problem is that the mmap control allows the appl_ptr
>>> being changed silently without interaction with the driver.  If the
>>> driver requires some explicit action for changing the appl_ptr, it
>>> won't work.
>>
>> I think 'struct snd_pcm_ops.pointer' is available for this purpose, too.
>>
>> static snd_pcm_sframes_t snd_pcm_playback_rewind(...)
>> {
>>     ...
>>     hw_avail = snd_pcm_playback_hw_avail(runtime);
>>     (->struct snd_pcm_ops.pointer())
>>     ...
>>     (rewind PCM frames)
>>     ...
>> +   substream->ops->pointer(...);
>>     (->struct snd_pcm_ops.pointer())
>>     ...
>> }
>>
>> If drivers need to handle event to update the appl_ptr, it records
>> value of the appl_ptr, then compare it to current value to get the
>> updates.
>
> IIRC, the problem isn't about the forward / rewind but about the
> normal data transfer.  In mmap mode, we transfer data on the mmap
> buffer, and update appl_ptr via mmap control.  Both are done without
> notification to the driver (which is intentional for avoiding the
> context switching).
>
> So we want to disable this optimization and always notify to the
> driver.  Disabling mmap status/control is the straight hack as it
> falls back to ioctl and then the driver can know the change.

There's SNDRV_PCM_IOCTL_HW_SYNC command. In kernel land implementation, 
this command is handled with a call of 'struct snd_pcm_ops.pointer'.

In alsa-lib, this command is often executed in most cases to handle PCM 
frames.


Regards

Takashi Sakamoto
Takashi Iwai May 16, 2017, 6:34 a.m. UTC | #6
On Tue, 16 May 2017 08:24:39 +0200,
Takashi Sakamoto wrote:
> 
> On May 16 2017 15:18, Takashi Iwai wrote:
> > On Tue, 16 May 2017 07:57:30 +0200,
> > Takashi Sakamoto wrote:
> >>
> >> On May 16 2017 14:46, Takashi Iwai wrote:
> >>> In this case, the problem is that the mmap control allows the appl_ptr
> >>> being changed silently without interaction with the driver.  If the
> >>> driver requires some explicit action for changing the appl_ptr, it
> >>> won't work.
> >>
> >> I think 'struct snd_pcm_ops.pointer' is available for this purpose, too.
> >>
> >> static snd_pcm_sframes_t snd_pcm_playback_rewind(...)
> >> {
> >>     ...
> >>     hw_avail = snd_pcm_playback_hw_avail(runtime);
> >>     (->struct snd_pcm_ops.pointer())
> >>     ...
> >>     (rewind PCM frames)
> >>     ...
> >> +   substream->ops->pointer(...);
> >>     (->struct snd_pcm_ops.pointer())
> >>     ...
> >> }
> >>
> >> If drivers need to handle event to update the appl_ptr, it records
> >> value of the appl_ptr, then compare it to current value to get the
> >> updates.
> >
> > IIRC, the problem isn't about the forward / rewind but about the
> > normal data transfer.  In mmap mode, we transfer data on the mmap
> > buffer, and update appl_ptr via mmap control.  Both are done without
> > notification to the driver (which is intentional for avoiding the
> > context switching).
> >
> > So we want to disable this optimization and always notify to the
> > driver.  Disabling mmap status/control is the straight hack as it
> > falls back to ioctl and then the driver can know the change.
> 
> There's SNDRV_PCM_IOCTL_HW_SYNC command. In kernel land
> implementation, this command is handled with a call of 'struct
> snd_pcm_ops.pointer'.
> 
> In alsa-lib, this command is often executed in most cases to handle
> PCM frames.

The HWSYNC or SYNC_PTR ioctls are used only as the fallback when mmap
failed.  It's the exact goal of this patch :)


Takashi
Takashi Sakamoto May 16, 2017, 6:54 a.m. UTC | #7
On May 16 2017 15:34, Takashi Iwai wrote:
>>> IIRC, the problem isn't about the forward / rewind but about the
>>> normal data transfer.  In mmap mode, we transfer data on the mmap
>>> buffer, and update appl_ptr via mmap control.  Both are done without
>>> notification to the driver (which is intentional for avoiding the
>>> context switching).
>>>
>>> So we want to disable this optimization and always notify to the
>>> driver.  Disabling mmap status/control is the straight hack as it
>>> falls back to ioctl and then the driver can know the change.
>>
>> There's SNDRV_PCM_IOCTL_HW_SYNC command. In kernel land
>> implementation, this command is handled with a call of 'struct
>> snd_pcm_ops.pointer'.
>>
>> In alsa-lib, this command is often executed in most cases to handle
>> PCM frames.
>
> The HWSYNC or SYNC_PTR ioctls are used only as the fallback when mmap
> failed.  It's the exact goal of this patch :)

Although SYNC_PTR is in the fallback mechanism of alsa-lib, HWSYNC is 
not in.

(alsa-lib)
ioctl(SNDRV_PCM_IOCTL_HWSYNC)
<-snd_pcm_hw_hw_sync()
= struct snd_pcm_fast_ops.hwsync
   <-__snd_pcm_hw_hwsync()
     <-snd_pcm_hwsync()
     <-snd_pcm_avail()
       <-snd_pcm_read_areas()
         <-snd_pcm_mmap_readi()
         <-snd_pcm_mmap_readn()
     <-snd_pcm_avail_delay()
     <-snd_pcm_write_areas()
       <-snd_pcm_mmap_writei()
       <-snd_pcm_mmap_writen()

For a case that applications execute ioctl(2) with 
SNDRV_PCM_IOCTL_READN/READI/WRITEN/WRITEI, in kernel land 
snd_pcm_lib_read1()/snd_pcm_lib_write1() should have calls of 'struct 
snd_pcm_ops.pointer', I think.


Regards

Takashi Sakamoto
Takashi Iwai May 16, 2017, 7:02 a.m. UTC | #8
On Tue, 16 May 2017 08:54:17 +0200,
Takashi Sakamoto wrote:
> 
> On May 16 2017 15:34, Takashi Iwai wrote:
> >>> IIRC, the problem isn't about the forward / rewind but about the
> >>> normal data transfer.  In mmap mode, we transfer data on the mmap
> >>> buffer, and update appl_ptr via mmap control.  Both are done without
> >>> notification to the driver (which is intentional for avoiding the
> >>> context switching).
> >>>
> >>> So we want to disable this optimization and always notify to the
> >>> driver.  Disabling mmap status/control is the straight hack as it
> >>> falls back to ioctl and then the driver can know the change.
> >>
> >> There's SNDRV_PCM_IOCTL_HW_SYNC command. In kernel land
> >> implementation, this command is handled with a call of 'struct
> >> snd_pcm_ops.pointer'.
> >>
> >> In alsa-lib, this command is often executed in most cases to handle
> >> PCM frames.
> >
> > The HWSYNC or SYNC_PTR ioctls are used only as the fallback when mmap
> > failed.  It's the exact goal of this patch :)
> 
> Although SYNC_PTR is in the fallback mechanism of alsa-lib, HWSYNC is
> not in.
> 
> (alsa-lib)
> ioctl(SNDRV_PCM_IOCTL_HWSYNC)
> <-snd_pcm_hw_hw_sync()
> = struct snd_pcm_fast_ops.hwsync
>   <-__snd_pcm_hw_hwsync()
>     <-snd_pcm_hwsync()
>     <-snd_pcm_avail()
>       <-snd_pcm_read_areas()
>         <-snd_pcm_mmap_readi()
>         <-snd_pcm_mmap_readn()
>     <-snd_pcm_avail_delay()
>     <-snd_pcm_write_areas()
>       <-snd_pcm_mmap_writei()
>       <-snd_pcm_mmap_writen()
> 
> For a case that applications execute ioctl(2) with
> SNDRV_PCM_IOCTL_READN/READI/WRITEN/WRITEI, in kernel land
> snd_pcm_lib_read1()/snd_pcm_lib_write1() should have calls of 'struct
> snd_pcm_ops.pointer', I think.

It's about the less-optimized code path with snd_pcm_mmap_read/write.
For the code path calling snd_pcm_mmap_begin() /
snd_pcm_mmap_commit(), there is no hwsync ioctl call.


Takashi
Takashi Sakamoto May 16, 2017, 10:55 a.m. UTC | #9
On May 16 2017 16:02, Takashi Iwai wrote:
> On Tue, 16 May 2017 08:54:17 +0200,
> Takashi Sakamoto wrote:
>>
>> On May 16 2017 15:34, Takashi Iwai wrote:
>>>>> IIRC, the problem isn't about the forward / rewind but about the
>>>>> normal data transfer.  In mmap mode, we transfer data on the mmap
>>>>> buffer, and update appl_ptr via mmap control.  Both are done without
>>>>> notification to the driver (which is intentional for avoiding the
>>>>> context switching).
>>>>>
>>>>> So we want to disable this optimization and always notify to the
>>>>> driver.  Disabling mmap status/control is the straight hack as it
>>>>> falls back to ioctl and then the driver can know the change.
>>>>
>>>> There's SNDRV_PCM_IOCTL_HW_SYNC command. In kernel land
>>>> implementation, this command is handled with a call of 'struct
>>>> snd_pcm_ops.pointer'.
>>>>
>>>> In alsa-lib, this command is often executed in most cases to handle
>>>> PCM frames.
>>>
>>> The HWSYNC or SYNC_PTR ioctls are used only as the fallback when mmap
>>> failed.  It's the exact goal of this patch :)
>>
>> Although SYNC_PTR is in the fallback mechanism of alsa-lib, HWSYNC is
>> not in.
>>
>> (alsa-lib)
>> ioctl(SNDRV_PCM_IOCTL_HWSYNC)
>> <-snd_pcm_hw_hw_sync()
>> = struct snd_pcm_fast_ops.hwsync
>>   <-__snd_pcm_hw_hwsync()
>>     <-snd_pcm_hwsync()
>>     <-snd_pcm_avail()
>>       <-snd_pcm_read_areas()
>>         <-snd_pcm_mmap_readi()
>>         <-snd_pcm_mmap_readn()
>>     <-snd_pcm_avail_delay()
>>     <-snd_pcm_write_areas()
>>       <-snd_pcm_mmap_writei()
>>       <-snd_pcm_mmap_writen()
>>
>> For a case that applications execute ioctl(2) with
>> SNDRV_PCM_IOCTL_READN/READI/WRITEN/WRITEI, in kernel land
>> snd_pcm_lib_read1()/snd_pcm_lib_write1() should have calls of 'struct
>> snd_pcm_ops.pointer', I think.
>
> It's about the less-optimized code path with snd_pcm_mmap_read/write.
> For the code path calling snd_pcm_mmap_begin() /
> snd_pcm_mmap_commit(), there is no hwsync ioctl call.

Indeed. I recalled it from my memory just after posting the previous 
message. In a case of the fallback, ioctl(2) with SYNC_PTR is surely 
executed:

ioctl(SNDRV_PCM_IOCTL_SYNC_PTR)
<-snd_pcm_hw_hw_mmap_commit)
= struct snd_pcm_fast_ops.mmap_commit()
   <-__snd_pcm_mmap_commit()
     <-snd_pcm_mmap_commit()

Now I agreed with the aim of this patch. In alsa-lib, 0 is passed as a 
'flags' option to ioctl(2) with SYNC_PTR in the call of 
snd_pcm_mmap_commit(). In kernel land, overhead to handle the ioctl is 
lighter than HWSYNC because hwptr is not synchronized.

However, in my opinion, disabling mmap the status and control data is 
exaggerated to the aim. SYNC_PTR ioctl is still available when page 
frame of these data is mapped. I can assume an idea to take alsa-lib to 
execute this command in snd_pcm_mmap_commit() when the NO_REWIND flag is 
enabled. Here, I assume that the flag and SYNC_PTR are tight coupling. 
(but we should concern about backward compatibility of relevant stuffs...)


By the way, at present, I think that this patchset may also be 
convenient to IEC 611883-1/6 engine and drivers in ALSA firewire stack. 
The engine is programmed to execute packetization in both of irq context 
of OHCI1394 isochronous context and process context of HWSYNC, to reduce 
packetization delay for PCM data substream. However, to the process 
context, this design expects applications to call ioctl(2) periodically 
with some commands; e.g. HWSYNC. As Iwai-san said, this ioctl command is 
not executed in snd_pcm_mmap_begin()/snd_pcm_mmap_commit() loop and I 
had concerns about it. (For example, PulseAudio is programmed to execute 
snd_pcm_avail() in the loop, but jackd isn't.) But I forgot it, oops :p


Thanks

Takashi Sakamoto

Patch
diff mbox

diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index c697ff90450d..dea7d89b41ca 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -284,6 +284,7 @@  enum {
 #define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
 #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
 #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
+#define SNDRV_PCM_INFO_NO_STATUS_MMAP	0x10000000	/* status and control mmap not supported */
 
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c14cdbd9ff86..2635a7d4d1fa 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3524,21 +3524,38 @@  static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
 	struct snd_pcm_file * pcm_file;
 	struct snd_pcm_substream *substream;	
 	unsigned long offset;
+	unsigned int info;
 	
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
+	info = substream->runtime->hw.info;
 
 	offset = area->vm_pgoff << PAGE_SHIFT;
 	switch (offset) {
 	case SNDRV_PCM_MMAP_OFFSET_STATUS:
 		if (pcm_file->no_compat_mmap)
 			return -ENXIO;
+		/*
+		 * force fallback to ioctl if driver doesn't support status
+		 * and control mmap.
+		 */
+		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
+			return -ENXIO;
+
 		return snd_pcm_mmap_status(substream, file, area);
 	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
 		if (pcm_file->no_compat_mmap)
 			return -ENXIO;
+
+		/*
+		 * force fallback to ioctl if driver doesn't support status
+		 * and control mmap.
+		 */
+		if (info & SNDRV_PCM_INFO_NO_STATUS_MMAP)
+			return -ENXIO;
+
 		return snd_pcm_mmap_control(substream, file, area);
 	default:
 		return snd_pcm_mmap_data(substream, file, area);