ASoC: core: Update ALSA core to issue restart in underrun.

When compressed and pcm session is started the buffer pull will
Be from the DSP, in mmap mode for the scenario Hardware pointer
Is same as application pointer implies application has not filled the
Buffer to be send to DSP, and platform driver has to break and restart
The de queue process when the application has sufficient buffers.

When hardware pointer is same as application pointer it is an under run
Scenario where the ALSA framework has to trigger the under run and in HAL
The session has to re-prepare and re-triggered. based on the stop
Threshold, but in our system the stop threshold is INT_MAX which
Indicates that under run is not triggered in practical cases.

We have a brodcast usecase in which the mentioned under run case
Is hit mulitple times, and every time re-prepare and re-trigger will be
Expensive

Update the ASoC core framework to restart de queue process stopped
By platform Driver when the under run is hit, based on the available
Buffer and render flag, so the System will recover from the hang state.

To restart de queue process the ASoC core will be calling the restart
Callback registered by platform driver and this callback will be running in
Atomic context.

Change-Id: Ic9ea05a0dc6246346e9913493232882e2f5447d1
Signed-off-by: Santosh Mardi <gsantosh@codeaurora.org>
This commit is contained in:
Santosh Mardi 2012-10-09 10:32:42 +05:30 committed by Stephen Boyd
parent 2347368881
commit dec3f44a64
2 changed files with 19 additions and 0 deletions

View file

@ -80,6 +80,7 @@ struct snd_pcm_ops {
unsigned long offset);
int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
int (*ack)(struct snd_pcm_substream *substream);
int (*restart)(struct snd_pcm_substream *substream);
};
/*
@ -110,6 +111,12 @@ struct snd_pcm_ops {
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
#define SNDRV_DMA_MODE (0)
#define SNDRV_NON_DMA_MODE (1 << 0)
#define SNDRV_RENDER_STOPPED (1 << 1)
#define SNDRV_RENDER_RUNNING (1 << 2)
/* If you change this don't forget to change rates[] table in pcm_native.c */
#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
@ -299,6 +306,7 @@ struct snd_pcm_runtime {
unsigned int rate_num;
unsigned int rate_den;
unsigned int no_period_wakeup: 1;
unsigned int render_flag;
/* -- SW params -- */
int tstamp_mode; /* mmap timestamp is updated */

View file

@ -2477,6 +2477,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
int err;
snd_pcm_uframes_t hw_avail;
memset(&sync_ptr, 0, sizeof(sync_ptr));
if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
@ -2499,6 +2500,16 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
control->avail_min = sync_ptr.c.control.avail_min;
else
sync_ptr.c.control.avail_min = control->avail_min;
if (runtime->render_flag & SNDRV_NON_DMA_MODE) {
hw_avail = snd_pcm_playback_hw_avail(runtime);
if ((hw_avail >= runtime->start_threshold)
&& (runtime->render_flag &
SNDRV_RENDER_STOPPED)) {
if (substream->ops->restart)
substream->ops->restart(substream);
}
}
sync_ptr.s.status.state = status->state;
sync_ptr.s.status.hw_ptr = status->hw_ptr;
sync_ptr.s.status.tstamp = status->tstamp;