[alsa-devel] mapping externally allocated Scatter Gather DMA buffers

Manu Abraham abraham.manu at gmail.com
Wed Dec 15 19:56:45 CET 2010


Hi,

Had some amount of success, but not completely functional yet.

at the moment, I do get a overrun (at least that's what arecord
claims). In fact after opening due to audio capture I do get the first
interrupt, but before the next interrupt arrives, arecord closes the
device and reopens the device (from the logs, I do see that the device
is being continuously opened and closed for each of those mentioned
overruns ?).

Eventually the device always ends up with an interrupt showing data
with the first 4 pages.

Any idea, why arecord keeps opening and closing for each overrun ?

Thanks,
Manu

testbox v4l # arecord -D plughw:2,0 --format S16_LE --rate=32000 -c 2
> /tmp/test.wav
Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 32000 Hz, Stereo
overrun!!! (at least 0.005 ms long)
overrun!!! (at least 0.002 ms long)
overrun!!! (at least 0.002 ms long)
overrun!!! (at least 0.003 ms long)
overrun!!! (at least 0.003 ms long)
overrun!!! (at least 0.001 ms long)
overrun!!! (at least 0.002 ms long)
overrun!!! (at least 0.001 ms long)
overrun!!! (at least 0.001 ms long)
overrun!!! (at least 0.001 ms long)
overrun!!! (at least 0.001 ms long)
overrun!!! (at least 0.001 ms long)


testbox v4l # cat /var/log/messages |grep evhandler
Dec 15 23:33:26 testbox kernel: [22380.791159] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.807889] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.824799] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.840634] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.856821] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.872661] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.888827] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.904667] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6
Dec 15 23:33:26 testbox kernel: [22380.920849] saa7231_audio_evhandler
(0): DEBUG: got buffer with index:1 port:6


[22395.146703] saa7231_irq_handler (0): status=0x800 vector=43
event=43 handler:f83d63a6
[22395.146716] saa7231_audio_evhandler (0): DEBUG: got buffer with
index:1 port:6
[22395.146734] saa7231_capture_pointer (0): DEBUG:()
[22395.146737] saa7231_capture_trigger (0): Trying to STOP stream, cmd=0

[22395.146780] saa7231_capture_prepare (0): ()
[22395.146783] saa7231_capture_prepare (0): Trying to Acquire stream
with 4096 lines per stream buffer
[22395.146786] saa7231_xs2dtl_acquire (0): Activating clock ..
mode=0x01, port_id=0x06
[22395.146788] saa7231_activate_clocks (0): DEBUG: Activating Clock
for Mode=0x01, port=0x06
[22395.146793] saa7231_activate_clocks (0): INFO:
tmIActivateSystemUseCase noticed active use case!
[22395.146806] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[22395.157028] saa7231_capture_trigger (0): Trying to START stream, cmd=1
[22395.157031] saa7231_xs2dtl_run (0): module=0x124000 Run
[22395.162525] saa7231_irq_handler (0): status=0x800 vector=43
event=43 handler:f83d63a6
[22395.162537] saa7231_audio_evhandler (0): DEBUG: got buffer with
index:1 port:6
[22395.162551] saa7231_capture_pointer (0): DEBUG:()
[22395.162553] saa7231_capture_trigger (0): Trying to STOP stream, cmd=0

[22395.162586] saa7231_capture_prepare (0): ()
[22395.162588] saa7231_capture_prepare (0): Trying to Acquire stream
with 4096 lines per stream buffer
[22395.162591] saa7231_xs2dtl_acquire (0): Activating clock ..
mode=0x01, port_id=0x06
[22395.162593] saa7231_activate_clocks (0): DEBUG: Activating Clock
for Mode=0x01, port=0x06
[22395.162598] saa7231_activate_clocks (0): INFO:
tmIActivateSystemUseCase noticed active use case!
[22395.162611] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[22395.173028] saa7231_capture_trigger (0): Trying to START stream, cmd=1
[22395.173032] saa7231_xs2dtl_run (0): module=0x124000 Run
[22395.178682] saa7231_irq_handler (0): status=0x800 vector=43
event=43 handler:f83d63a6
[22395.178695] saa7231_audio_evhandler (0): DEBUG: got buffer with
index:1 port:6
[22395.178714] saa7231_capture_pointer (0): DEBUG:()
[22395.178716] saa7231_capture_trigger (0): Trying to STOP stream, cmd=0

[22395.178759] saa7231_capture_prepare (0): ()
[22395.178762] saa7231_capture_prepare (0): Trying to Acquire stream
with 4096 lines per stream buffer
[22395.178765] saa7231_xs2dtl_acquire (0): Activating clock ..
mode=0x01, port_id=0x06
[22395.178767] saa7231_activate_clocks (0): DEBUG: Activating Clock
for Mode=0x01, port=0x06
[22395.178772] saa7231_activate_clocks (0): INFO:
tmIActivateSystemUseCase noticed active use case!
[22395.178785] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[22395.189028] saa7231_capture_trigger (0): Trying to START stream, cmd=1
[22395.189030] saa7231_xs2dtl_run (0): module=0x124000 Run
[22395.194864] saa7231_irq_handler (0): status=0x800 vector=43
event=43 handler:f83d63a6
[22395.194877] saa7231_audio_evhandler (0): DEBUG: got buffer with
index:1 port:6
[22395.194893] saa7231_capture_pointer (0): DEBUG:()
[22395.194896] saa7231_capture_trigger (0): Trying to STOP stream, cmd=0

[22395.194932] saa7231_capture_prepare (0): ()
[22395.194934] saa7231_capture_prepare (0): Trying to Acquire stream
with 4096 lines per stream buffer
[22395.194937] saa7231_xs2dtl_acquire (0): Activating clock ..
mode=0x01, port_id=0x06
[22395.194939] saa7231_activate_clocks (0): DEBUG: Activating Clock
for Mode=0x01, port=0x06
[22395.194944] saa7231_activate_clocks (0): INFO:
tmIActivateSystemUseCase noticed active use case!
[22395.194957] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[22395.206170] saa7231_hw_free (0): DEBUG: Removing IRQ event ..
[22395.206174] saa7231_remove_irqevent (0): Removing IRQ Event:43 ......
[22395.206176] saa7231_remove_irqevent (0): IRQ Event 43 <AS2D_AVIS> removed
[22395.206202] saa7231_hw_free (0): DEBUG: Removing IRQ event ..
[22395.206242] saa7231_remove_irqevent (0): Removing IRQ Event:43 ......
[22395.206244] saa7231_capture_close (0): DEBUG: Closing stream

static struct snd_pcm_hardware saa7231_capture_info = {
	.info			= (SNDRV_PCM_INFO_MMAP		|
				  SNDRV_PCM_INFO_INTERLEAVED	|
				  SNDRV_PCM_INFO_BLOCK_TRANSFER	|
				  SNDRV_PCM_INFO_MMAP_VALID),

	.formats		= (SNDRV_PCM_FMTBIT_S16_LE	|
				  SNDRV_PCM_FMTBIT_S16_BE	|
				  SNDRV_PCM_FMTBIT_S8		|
				  SNDRV_PCM_FMTBIT_U8		|
				  SNDRV_PCM_FMTBIT_U16_LE	|
				  SNDRV_PCM_FMTBIT_U16_BE),

	.rates			= SNDRV_PCM_RATE_32000,

	.rate_min		= 32000,
	.rate_max		= 48000,

	.channels_min		= 1,
	.channels_max		= 2,

	.buffer_bytes_max	= XS2D_BUFFERS * PAGE_SIZE * 512,

	.period_bytes_min	= 4096,
	.period_bytes_max	= 2097152,

	.periods_min		= 8,
	.periods_max		= 4096,
};

static int saa7231_audio_evhandler(struct saa7231_dev *saa7231, int vector)
{
	struct saa7231_audio *audio	= saa7231->audio;
	struct saa7231_stream *stream	= audio->stream;

	int index = 0, err = 0;

	if (stream->ops.get_buffer) {
		err = stream->ops.get_buffer(stream, &index);
		if (err)
			dprintk(SAA7231_ERROR, 1, "ERROR: get_buffer failed, err=%d", err);

		dprintk(SAA7231_DEBUG, 1, "DEBUG: got buffer with index:%d port:%d",
index, stream->port_id);
	}
	audio->index = index;
	queue_work(saa7231->wq, &audio->irq_pending_work);
	return 0;
}

static void saa7231_audio_irq_work(struct work_struct *work)
{
	struct saa7231_audio *audio = container_of(work, struct
saa7231_audio, irq_pending_work);

	snd_pcm_period_elapsed(audio->pcm);
}

static snd_pcm_uframes_t saa7231_capture_pointer(struct snd_pcm_substream *pcm)
{
	struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
	struct saa7231_dev *saa7231	= audio->saa7231;
	struct snd_pcm_runtime *rt	= pcm->runtime;

	dprintk(SAA7231_DEBUG, 1, "DEBUG:()");
	return bytes_to_frames(rt, audio->index * audio->pages * PAGE_SIZE);
}

static int saa7231_hw_params(struct snd_pcm_substream *pcm, struct
snd_pcm_hw_params *params)
{
	struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
	struct saa7231_dev *saa7231	= audio->saa7231;
	struct snd_pcm_runtime *rt	= pcm->runtime;

	struct saa7231_dmabuf *buffer;
	struct saa7231_stream *stream;
	struct avis_audio *decoder;
	struct avis_audio_ops *ops;
	struct audio_config config;

	struct saa7231_dmabuf *dmabuf;
	struct page **ptable;

	void *mem;
	void *dma_area;

	int ret, i, j, pages, bytes, periods, bufsiz, idx;

#define MAX_ENTRIES_PER_PAGE		(PAGE_SIZE / 8)
#define PAGES_PER_XS2D(__pages)		(__pages / XS2D_BUFFERS)
#define BUFSIZE_PER_XS2D(__size)	(__size / XS2D_BUFFERS)

	dprintk(SAA7231_DEBUG, 1, "DEBUG: ()");

	periods = params_periods(params);
	bytes   = params_period_bytes(params);
	bufsiz  = params_buffer_bytes(params);
	pages	= snd_sgbuf_aligned_pages(bufsiz);

	audio->bufsize	= bufsiz;
	audio->periods	= periods;
	audio->bytes	= bytes;
	audio->pages	= pages;

	dprintk(SAA7231_DEBUG, 1, "bufsiz=%d periods=%d bytes=%d pages=%d",
		bufsiz,
		periods,
		bytes,
		pages);

	/* enable stream */
	/* initializing 8 buffer with "pages" pages each .. */
	stream = saa7231_stream_init(saa7231, AUDIO_CAPTURE, ADAPTER_INT, 0,
(pages / XS2D_BUFFERS));
	if (!stream) {
		dprintk(SAA7231_ERROR, 1, "ERROR: Registering stream");
		ret = -ENOMEM;
		goto err;
	}
	audio->stream = stream;
	buffer = stream->dmabuf;
	mutex_lock(&saa7231->dev_lock);

	saa7231_add_irqevent(saa7231, 43, SAA7231_EDGE_RISING,
saa7231_audio_evhandler, "AS2D_AVIS");
	dprintk(SAA7231_DEBUG, 1, "Mapping %d buffers with %d pages each",
XS2D_BUFFERS, PAGES_PER_XS2D(pages));

	dprintk(SAA7231_DEBUG, 1, "Page Table array size=%d", pages);
	ptable = kzalloc((sizeof (struct page) * pages), GFP_KERNEL);
	if (!ptable) {
		dprintk(SAA7231_ERROR, 1, "ERROR: No memory to allocate virtual map");
		ret = -ENOMEM;
		goto err;
	}
	audio->ptable = ptable;
	idx = 0;

	for (i = 0; i < XS2D_BUFFERS; i ++) {
		dmabuf = &buffer[i];
		mem = dmabuf->vmalloc;
		for (j = 0; j < PAGES_PER_XS2D(pages); j++) {
			BUG_ON(idx > pages);
			dprintk(SAA7231_DEBUG, 1, "Mapping Page:%d from XS2D_BUFFER:%d to
PTA Offset:%d", j, i, idx);
			ptable[idx] = virt_to_page(mem);
			mem += PAGE_SIZE;
			idx += 1;
		}
	}

	dma_area = vmap(ptable, pages, VM_MAP, PAGE_KERNEL);
	rt->dma_area	= dma_area;
	rt->dma_bytes	= pages * PAGE_SIZE;
	rt->dma_addr	= 0;

	config.srate	= SRATE_32k;		/* default sample rate */
	config.source	= AUDIOSRC_CVBS1;	/* default source */
	config.l_volume	= VOL_MAX;
	config.r_volume = VOL_MAX;

	ret = saa7231_audio_attach(stream, &config);
	if (ret) {
		dprintk(SAA7231_ERROR, 1, "Audio decoder attach failed, err=%d", ret);
		goto err;
	}

	decoder	= stream->adec;
	ops	= &decoder->ops;

	decoder->port = AUDIOPORT_DAC1;

	if (ops->powerup) {
		ret = ops->powerup(stream);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "Failed to power up, err=%d", ret);
			ret = -EIO;
			goto err;
		}
	}

	if (ops->open) {
		ret = ops->open(stream);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "Failed to open stream, err=%d", ret);
			return -EIO;
		}
	}

	if (ops->ena_port) {
		ret = ops->ena_port(stream, AUDIOPORT_SPDIF, 1);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "Failed to enable port, err=%d", ret);
			return -EIO;
		}
	}

	if (ops->set_src) {
		ret = ops->set_src(stream, AUDIOSRC_CVBS1);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "Failed to enable source, err=%d", ret);
			return -EIO;
		}
	}

err:
	mutex_unlock(&saa7231->dev_lock);
	return ret;
}












On Fri, Nov 12, 2010 at 1:35 PM, Jaroslav Kysela <perex at perex.cz> wrote:
> On Fri, 12 Nov 2010, Manu Abraham wrote:
>
>> On Thu, Nov 11, 2010 at 6:04 PM, Manu Abraham <abraham.manu at gmail.com>
>> wrote:
>>>
>>> On Thu, Nov 11, 2010 at 4:00 PM, Jaroslav Kysela <perex at perex.cz> wrote:
>>>>
>>>> On Thu, 11 Nov 2010, Manu Abraham wrote:
>>>>
>>>>> On Wed, Nov 10, 2010 at 11:35 PM, Jaroslav Kysela <perex at perex.cz>
>>>>> wrote:
>>>
>>>>>
>>>>> I adapted the whole thing to make the buffersize divided amongst the
>>>>> XS2D_BUFFERS (8):
>>>>
>>>> Probably yes.
>>>>
>>>>> I hope the mapping of the buffers is okay ? It looks thus, now ..
>>>>
>>>> From information you sent me about hw privately, I think that the
>>>> period_bytes must be 4096 or multiple of this value with minumum count
>>>> of
>>>> periods 8 (or multiple of 8). Otherwise you get a non-continuous memory
>>>> area
>>>> (the hw uses only portion of system memory page, thus there'll be gaps).
>>>> The
>>>> problem is that we have MMAP_COMPLEX mode, but no application can handle
>>>> (does not implement) this mmap mode and I'm not sure, if we can even
>>>> describe the DMA buffer size layout for this case for your specific hw.
>>>>
>>>> I would use:
>>>>
>>>>        snd_pcm_hw_constraint_step(runtime, 0,
>>>> SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
>>>>                                  4096);
>>>>
>>>>
>>>>        snd_pcm_hw_constraint_step(runtime, 0,
>>>> SNDRV_PCM_HW_PARAM_PERIODS,
>>>>                                   8);
>>>>
>>>> And define periods_min = 8 (max to multiple 8 - choose your max limit)
>>>> and
>>>> period_bytes_min to 4096 (max to multiple 4096 - choose your max limit).
>>>>
>>>> Note that -EIO means that your driver does not called
>>>> snd_pcm_period_elapsed() and/or the pointer callback returns wrong
>>>> position
>>>> to the audio ring buffer.
>>>
>>>
>>>
>>> Ok, modified it, also added in code to acquire the stream, It's a bit
>>> more complete now.
>>> The crazy part that I do see now, is that I see an inconsistent lock
>>> state with the hda_intel
>>> driver which is the soundcard on my system. But I don't understand why
>>> the locking on it
>>> has to become inconsistent on loading this driver.
>>
>>
>> Ok, I found the reason: I was passing a single page for the
>> page_table, which I guess corrupted the whole stack !!
>>
>> Eventually, I fixed the same. but ran into another issue ? Should
>> trigger not sleep or something that way ?
>> Currently, I see the issue as follows in the log, but if the
>> ops->run() callback is commented out I don't get that
>> weird message/error about lock states.
>>
>> Now, ops->run(), ie xs2dtl_run() is called with other other streams,
>> such as an MPEG stream, where it doesn't
>> show any issues.
>>
>> Any idea, why uncommenting ops->run() produces that message ? Should
>> trigger not sleep ? Confused ...
>
> Trigger must be fast without any sleeping. Only fast spinlocks are allowed.
> If you need sleep, just activate a tasklet and do the start job in the
> tasklet or a thread.
>
>                                                Jaroslav
>
> -----
> Jaroslav Kysela <perex at perex.cz>
> Linux Kernel Sound Maintainer
> ALSA Project, Red Hat, Inc.
>


More information about the Alsa-devel mailing list