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

Manu Abraham abraham.manu at gmail.com
Thu Nov 11 13:34:20 CET 2010


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.

Eventually it looks thus:




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,
};

/*
 * 10mS Buffer lengths
 * @48kHz	1920 bytes
 * @44.1kHz	1764 bytes
 * @32kHz	1280 bytes
 *
 *
 * period min = 10mS @48k:  1920 bytes @44.1k:  1764 bytes @32k:  1280 bytes
 * period max = 1S   @48k:192000 bytes @44.1k:176400 bytes @32k:128000 bytes
 * period     = 4S   @48k:768000 bytes @44.1k:705600 bytes @32k:512000 bytes
 */
static int saa7231_capture_open(struct snd_pcm_substream *pcm)
{
        struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
        struct snd_pcm_runtime *rt	= pcm->runtime;
	struct saa7231_dev *saa7231	= audio->saa7231;
        int err;

	dprintk(SAA7231_DEBUG, 1, "()");
	rt->hw = saa7231_capture_info;
	snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraint_rates);
	err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
        if (err < 0) {
		dprintk(SAA7231_ERROR, 1, "snd_pcm_hw_constraint_integer() failed.
ret=%d", err);
                return err;
	}

	err = snd_pcm_hw_constraint_step(rt, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4096);
	if (err < 0) {
		dprintk(SAA7231_ERROR, 1, "snd_pcm_hw_constraint_minmax() failed.
ret=%d", err);
		return err;
	}
	err = snd_pcm_hw_constraint_step(rt, 0, SNDRV_PCM_HW_PARAM_PERIODS, 8);
	if (err < 0) {
		dprintk(SAA7231_ERROR, 1, "snd_pcm_hw_constraint_minmax() failed.
ret=%d", err);
		return err;
	}

        return 0;
}

/*
 * saa7231_hw_params()
 *
 * This callback is called when the hardware parameter (hw_params) is setup
 * by the application, ie., once when the buffer size, the period size,
 * the format etc are defined for the PCM substream.
 */
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 saa7231_dmabuf *dmabuf;

	struct page **ptable;

	void *mem;
	void *dma_area;

	int i, j, pages, bytes, periods, bufsiz, pt_size, 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   = (bufsiz + PAGE_SIZE - 1) / PAGE_SIZE;

	audio->bufsize = bufsiz;

	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");
		return -ENOMEM;
	}
	audio->stream = stream;
	buffer = stream->dmabuf;
	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));

	/*
	 * For a single DMA buffer:
	 * each page takes a u64 size in a page table
	 * number of entries a single page can hold = PAGE_SIZE / entry size
	 * ie entries.max = PAGE_SIZE / 8 => 4096/8 = 512
	 * Now, we have entries.req = 7 ("pages") per buffer
	 *
	 * For all in XS2D_BUFFERS:
	 * page table should be large enough to hold all the pages in each DMA buffer
	 * total number of pages = pages * XS2D_BUFFERS
	 * max buffers that we need to consider = 512 * 8, this needs 8 pages
for a page table
	 *
	 * On a general note, we can calculate pages for page table as
	 * page_table_size = total_pages / 512, with a minimum of a single page
	 */

	pt_size = (pages * XS2D_BUFFERS) / MAX_ENTRIES_PER_PAGE;
	/* minimum 1 page required for the table */
	if (pt_size < 1)
		pt_size = 1;

	dprintk(SAA7231_DEBUG, 1, "Page Table array size=%d", pt_size);
	ptable = kzalloc((sizeof (struct page) * pt_size), GFP_KERNEL);
	if (!ptable) {
		dprintk(SAA7231_ERROR, 1, "ERROR: No memory to allocate virtual map");
		return -ENOMEM;
	}
	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;

	return 0;
}

/*
 * saa7231_hw_free()
 *
 * This callback is called to release the resources allocated via hw_params.
 * For eg: releasing the buffer via snd_pcm_lib_malloc_pages() is done by
 * snd_pcm_lib_free_pages(substream)
 * This function is always called before the close callback is called. Also,
 * the callback maybe called multiple times.
 */
static int saa7231_hw_free(struct snd_pcm_substream *pcm)
{
	struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
	struct saa7231_dev *saa7231	= audio->saa7231;
	struct saa7231_stream *stream	= audio->stream;
	struct page **ptable		= audio->ptable;
	struct snd_pcm_runtime *rt	= pcm->runtime;
	void *dma_area			= rt->dma_area;

	dprintk(SAA7231_DEBUG, 1, "DEBUG: Removing IRQ event ..");
	saa7231_remove_irqevent(saa7231, 43);

	if (dma_area) {
		dprintk(SAA7231_DEBUG, 1, "DEBUG: Unmap Virtual memory region ..");
		vunmap(dma_area);
	}
	dprintk(SAA7231_DEBUG, 1, "DEBUG: Stream exiting ..");
	saa7231_stream_exit(stream);

	dprintk(SAA7231_DEBUG, 1, "DEBUG: Freeing ptable ...");
	kfree(ptable);
	return 0;
}

/*
 * saa7231_capture_prepare()
 *
 * This callback is called when the PCM is prepared. You can set the format
 * type, sample rate, etc here. The difference from hw_params is that the
 * prepare callback will be called each time snd_pcm_prepare() is called,
 * ie, when recovering from underruns.
 */
static int saa7231_capture_prepare(struct snd_pcm_substream *pcm)
{
	struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
	struct saa7231_dev *saa7231	= audio->saa7231;
	struct saa7231_stream *stream	= audio->stream;
	struct stream_ops *ops		= &stream->ops;

	u32 bps, spl, pitch, buflen;
	int err;

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

	bps	= 16;
	spl	= 2;
	pitch	= spl * bps / 8;
	buflen	= BUFSIZE_PER_XS2D(audio->bufsize);

	stream->params.bps	= bps;
	stream->params.spl	= spl;
	stream->params.pitch	= pitch;
	stream->params.lines	= buflen / pitch;
	stream->params.type	= STREAM_AUDIO;

	dprintk(SAA7231_DEBUG, 1, "Trying to Acquire stream with %dlines per
stream buffer", stream->params.lines);
	if (ops->acquire) {
		err = ops->acquire(stream);
		if (err) {
			dprintk(SAA7231_ERROR, 1, "ERROR: acquiring stream, err=%d", err);
			return -EIO;
		}
	}
	return 0;
}

/*
 * saa7231_capture_trigger()
 *
 * This callback is called when the PCM is started, stoppped or paused.
 */
static int saa7231_capture_trigger(struct snd_pcm_substream *pcm, int cmd)
{
	struct saa7231_audio *audio	= snd_pcm_substream_chip(pcm);
	struct saa7231_dev *saa7231	= audio->saa7231;
	struct saa7231_stream *stream	= audio->stream;
	struct stream_ops *ops		= &stream->ops;
	int err;

	switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
		dprintk(SAA7231_DEBUG, 1, "Tring to START stream, cmd=%d", cmd);
		if (ops->run) {
			err = ops->run(stream);
			if (err) {
				dprintk(SAA7231_ERROR, 1, "ERROR: starting stream, err=%d", err);
				return -EIO;
			}
		}
		break;
        case SNDRV_PCM_TRIGGER_STOP:
		dprintk(SAA7231_DEBUG, 1, "Tring to STOP stream, cmd=%d", cmd);
		if (ops->stop) {
			err = ops->stop(stream);
			if (err) {
				dprintk(SAA7231_ERROR, 1, "ERROR: stopping stream, err=%d", err);
				return -EIO;
			}
		}
		break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_SUSPEND:
		dprintk(SAA7231_DEBUG, 1, "Tring to PAUSE stream, cmd=%d", cmd);
		if (ops->pause) {
			err = ops->pause(stream);
			if (err) {
				dprintk(SAA7231_ERROR, 1, "ERROR: pausing stream, err=%d", err);
				return -EIO;
			}
		}
		break;
	default:
		dprintk(SAA7231_DEBUG, 1, "Unknown command, cmd=%d", cmd);
		snd_BUG();
		return -EINVAL;
	}
	return 0;
}

/*
 * saa7231_capture_pointer()
 *
 * This callback is called when the PCM middle layer inquires the current
 * hardware position on the buffer. The position must be returned in frames,
 * ranging from 0 to buffer_size - 1.
 * This is usually called from the buffer-update routine in the PCM middle
 * layer, which is invoked when snd_pcm_period_elapsed() is called in the
 * interrupt routine. The PCM middle layer then updates the position and
 * calculates the available space, wakes up poll threads etc
 */
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;

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

	return 0; //bytes_to_frames(rt, played);
}

/**
 * Initialiaze a stream port, for the required port
 */
struct saa7231_stream *saa7231_stream_init(struct saa7231_dev *saa7231,
					   enum saa7231_mode mode,
					   enum adapter_type adap_type,
					   int count,
					   int pages)
{
	int ret;
	struct saa7231_stream *stream;
	struct saa7231_dtl *dtl;

	stream = kzalloc(sizeof(struct saa7231_stream), GFP_KERNEL);
	if (!stream) {
		dprintk(SAA7231_ERROR, 1, "ERROR: Failed allocating streams");
		return NULL;
	}
	stream->mode	= mode;
	stream->saa7231 = saa7231;
	dtl 		= &stream->dtl;

	dprintk(SAA7231_DEBUG, 1, "DEBUG: Initializing Stream with MODE=0x%02x", mode);

	switch (mode) {
	case AUDIO_CAPTURE:
		if (count >= 1) {
			dprintk(SAA7231_ERROR, 1, "ERROR: Invalid Stream port, port=%d", count);
			return NULL;
		}

		switch (adap_type) {
		case ADAPTER_INT:
			stream->port_id	= STREAM_PORT_AS2D_LOCAL;
			dtl->module	= AS2D_LOCAL;
			break;
		case ADAPTER_EXT:
			stream->port_id	= STREAM_PORT_AS2D_EXTERN;
			dtl->module	= AS2D_EXTERN;
			break;
		}

		ret = saa7231_xs2dtl_init(stream, pages);
		if (ret < 0) {
			dprintk(SAA7231_ERROR, 1, "ERROR: XS2DTL engine initialization failed");
			return NULL;
		}
		break;
	case VIDEO_CAPTURE:
		if (count >= 1) {
			dprintk(SAA7231_ERROR, 1, "ERROR: Invalid Stream port, port=%d", count);
			return NULL;
		}

		switch (adap_type) {
		case ADAPTER_INT:
			stream->port_id	= STREAM_PORT_VS2D_AVIS;
			dtl->module	= VS2D_AVIS;
			break;
		case ADAPTER_EXT:
			stream->port_id	= STREAM_PORT_VS2D_ITU;
			dtl->module	= VS2D_ITU;
			break;
		}

		ret = saa7231_vs2dtl_init(stream, pages);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "ERROR: VS2DTL engine initialization failed");
			return NULL;
		}
		ret = saa7231_avis_attach(stream);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "ERROR: AVIS initialization, attach() failed");
			return NULL;
		}
		break;
	case VBI_CAPTURE:
		if (count >= 1) {
			dprintk(SAA7231_ERROR, 1, "ERROR: Invalid Stream port, port=%d", count);
			return NULL;
		}

		switch (adap_type) {
		case ADAPTER_INT:
			stream->port_id	= STREAM_PORT_DS2D_AVIS;
			dtl->module	= DS2D_AVIS;
			break;
		case ADAPTER_EXT:
			stream->port_id	= STREAM_PORT_DS2D_ITU;
			dtl->module	= DS2D_ITU;
			break;
		}

		ret = saa7231_xs2dtl_init(stream, pages);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "ERROR: XS2DTL engine initialization failed");
			return NULL;
		}
		break;
	case DIGITAL_CAPTURE:
		if (count >= 2) {
			dprintk(SAA7231_ERROR, 1, "ERROR: Invalid Stream port, port=%d", count);
			return NULL;
		}

		switch (adap_type) {
		case ADAPTER_INT:
			stream->port_id	= STREAM_PORT_TS2D_DTV0 + count;
			dtl->module	= TS2D0_DTV + (count * 0x1000);
			break;
		case ADAPTER_EXT:
			stream->port_id	= STREAM_PORT_TS2D_EXTERN0 + count;
			dtl->module	= TS2D0_EXTERN + (count * 0x1000);
			break;
		}

		ret = saa7231_xs2dtl_init(stream, pages);
		if (ret) {
			dprintk(SAA7231_ERROR, 1, "ERROR: XS2DTL engine initialization failed");
			return NULL;
		}
		BUG_ON(stream->ops.acquire == NULL);
		stream->params.bps   = 8;
		stream->params.spl   = 188;
		stream->params.lines = 348;
		stream->params.pitch = 188;
		stream->params.thrsh = 0;
		stream->params.flags = 0;
		stream->params.type  = STREAM_TS;
		ret = stream->ops.acquire(stream);
		if (ret < 0) {
			dprintk(SAA7231_ERROR, 1, "TS setup failed, ret=%d", ret);
			return NULL;
		}
		break;
	default:
		dprintk(SAA7231_ERROR, 1, "ERROR: Unknown mode=0x%02x", mode);
		BUG_ON(1);
		break;
	}

	/*
	 * Stream port starts at 0, but the related DMA channel is offset
	 * by +1, since MSI uses DMA channel 0. We store this offset as a
	 * mask
	 */
	dprintk(SAA7231_ERROR, 1, "INFO: Initialized MODE:0x%02x for PORT:%d",
		mode,
		stream->port_id);

	stream->init = 1;
	return stream;
}

int saa7231_xs2dtl_init(struct saa7231_stream *stream, int pages)
{
	int i, ret;
	struct stream_ops *ops		= &stream->ops;
	struct saa7231_dev *saa7231	= stream->saa7231;

	struct saa7231_dmabuf *dmabuf;

	dprintk(SAA7231_DEBUG, 1, "XS2DTL engine Initializing .....");
	/**
	 * Note: the stream port array starts at 0 but the related DMA
	 *       channel at dwDMAChannel +1, because MSI uses channel 0.
	 *       Store DMA enumeration but keep "+1" in channel mask!
	 */
	switch (stream->port_id) {
	case STREAM_PORT_DS2D_AVIS:
	case STREAM_PORT_DS2D_ITU:
		stream->port_hw = STREAM_VBI;
		stream->config	= 0;
		break;

	case STREAM_PORT_AS2D_LOCAL:
	case STREAM_PORT_AS2D_EXTERN:
		stream->port_hw = STREAM_AUDIO;
		stream->config	= 0x4; /* IIS stream */
		break;

	case STREAM_PORT_TS2D_DTV0:
	case STREAM_PORT_TS2D_DTV1:
		stream->port_hw = STREAM_TS;
		stream->config   = 0x0;
		break;

	case STREAM_PORT_TS2D_EXTERN0:
	case STREAM_PORT_TS2D_EXTERN1:
		stream->port_hw = STREAM_TS;
		stream->config	= 0x11; /* Parallel, Port ON */
		break;

	case STREAM_PORT_TS2D_CAM:
		stream->port_hw = STREAM_TS;
		stream->config	= 0x0181;
		break;

	default:
		dprintk(SAA7231_ERROR, 1, "ERROR: Invalid DMA setup!");
		stream->config	= 0;
		return -EINVAL;
	}
	/* Allocate space for n XS2D Buffers */
	dmabuf = kzalloc(sizeof (struct saa7231_dmabuf) * XS2D_BUFFERS, GFP_KERNEL);
	if (!dmabuf) {
		dprintk(SAA7231_ERROR, 1, "ERROR: Allocating %d XS2D Buffers", XS2D_BUFFERS);
		ret = -ENOMEM;
	}
	dprintk(SAA7231_DEBUG, 1, "Allocated %d XS2DTL Buffer @0x%p",
XS2D_BUFFERS, dmabuf);
	stream->dmabuf = dmabuf;

	dprintk(SAA7231_DEBUG, 1, "Allocating DMA Buffers ...");
	for (i = 0; i < XS2D_BUFFERS; i++) {
		dprintk(SAA7231_DEBUG, 1, "Allocating DMA buffer:%d @0x%p..", i, &dmabuf[i]);
		ret = saa7231_dmabuf_alloc(saa7231, &dmabuf[i], pages);
		if (ret < 0) {
			dprintk(SAA7231_ERROR, 1, "ERROR: Failed allocating DMA buffers,
error=%d", ret);
			return -ENOMEM;
		}
	}
	dprintk(SAA7231_DEBUG, 1, "Initializing PTA ...");
	saa7231_init_ptables(stream);

	dprintk(SAA7231_DEBUG, 1, "Setting up PORT Gates ...");
	/* deactivate gating */
	switch (stream->port_id) {
	case STREAM_PORT_DS2D_AVIS:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_VBI_LOC_CLGATE);
		break;
	case STREAM_PORT_DS2D_ITU:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_VIDEO_EXT_CLGATE);
		break;
	case STREAM_PORT_AS2D_LOCAL:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_AUDIO_LOC_CLGATE);
		break;
	case STREAM_PORT_AS2D_EXTERN:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_AUDIO_EXT_CLGATE);
		break;
	case STREAM_PORT_TS2D_DTV0:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TS0_LOC_CLGATE);
		break;
	case STREAM_PORT_TS2D_DTV1:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TS1_LOC_CLGATE);
		break;
	case STREAM_PORT_TS2D_EXTERN0:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TS0_EXT_CLGATE);
		break;
	case STREAM_PORT_TS2D_EXTERN1:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TS1_EXT_CLGATE);
		break;
	case STREAM_PORT_TS2D_CAM:
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TSCA_EXT_CLGATE);
		SAA7231_WR(0, SAA7231_BAR0, STREAM, STREAM_RA_TSMUX_CLGATE);

		/* TODO! disable clock usage here */
		break;
	default:
		return -EINVAL;
	}

	ops->acquire	= saa7231_xs2dtl_acquire;
	ops->run	= saa7231_xs2dtl_run;
	ops->pause	= saa7231_xs2dtl_pause;
	ops->stop	= saa7231_xs2dtl_stop;

	ops->set_buffer = saa7231_xs2dtl_set_buffer;
	ops->get_buffer = saa7231_xs2dtl_get_buffer;

	ops->exit 	= saa7231_xs2dtl_exit;

	return 0;
}

/**
 * Allocates one page of memory, which is stores the data of one
 * 7231 page table. The result gets stored in the passed DMA buffer
 * structure.
 */
static int saa7231_allocate_ptable(struct saa7231_dmabuf *dmabuf)
{
	struct saa7231_dev *saa7231	= dmabuf->saa7231;
	struct pci_dev *pdev		= saa7231->pdev;
	void *virt;
	dma_addr_t phys;

	virt = (void *) __get_free_page(GFP_KERNEL);
	if (!virt) {
		dprintk(SAA7231_ERROR, 1, "ERROR: Out of pages !");
		return -ENOMEM;
	}

	/*
	 * TODO!
	 * A conversion from virtual to physical is sufficient alone ?
	 * phys = __pa(virt)
	 * Or should we do DMA to the Page Table themselves ?
	 * In some some chip versions it seems we must manually copy the
	 * Page Tables, as Page Table DMA doesn't work ??
	 * Need to figure this out, as people who are really aware of this
	 * concept, can no longer be reached
	 */
	phys = dma_map_single(&pdev->dev,
			      virt,
			      SAA7231_PAGE_SIZE,
			      DMA_FROM_DEVICE);

	dprintk(SAA7231_DEBUG, 1, "Virtual 0x%p to Phys 0x%04x mapped page",
		virt,
		phys);

	if (!phys) {
		dprintk(SAA7231_ERROR, 1, "ERROR: map memory failed !");
		return -ENOMEM;
	}

	BUG_ON((unsigned long) phys % SAA7231_PAGE_SIZE);
	dmabuf->pt_phys = phys;
	dmabuf->pt_virt = virt;
	return 0;
}

/**
 * Create a SG, when an allocated buffer is passed to it,
 * otherwise the needed memory gets allocated by itself
 */
static int saa7231_dmabuf_sgalloc(struct saa7231_dmabuf *dmabuf, void
*buf, int pages)
{
	struct saa7231_dev *saa7231	= dmabuf->saa7231;
	struct scatterlist *sg_list;
	struct page *pg;
	void *vma = NULL, *mem = NULL;

	int i;

	BUG_ON(!pages);
	BUG_ON(!dmabuf);

	/* Allocate memory for SG list */
	sg_list = kzalloc(sizeof (struct scatterlist) * pages , GFP_KERNEL);
	if (!sg_list) {
		dprintk(SAA7231_ERROR, 1, "Failed to allocate memory for scatterlist.");
		return -ENOMEM;
	}
	sg_init_table(sg_list, pages);

	if (!buf) {
		/* allocate memory, unaligned, virtually contiguous memory region */
		mem = vmalloc((pages + 1) * SAA7231_PAGE_SIZE);
		if (!mem) {
			dprintk(SAA7231_ERROR, 1, "ERROR: vmalloc failed allocating %d
pages", pages);
			return -ENOMEM;
		}
		dprintk(SAA7231_INFO, 1, "Virtual contiguous %d byte region with %d
%dk pages",
			pages * SAA7231_PAGE_SIZE,
			pages,
			(SAA7231_PAGE_SIZE / 1024));

		/* align memory to page */
		vma = (void *) PAGE_ALIGN (((unsigned long) mem));
		BUG_ON(((unsigned long) vma) % SAA7231_PAGE_SIZE);
	} else {
		dprintk(SAA7231_DEBUG, 1, "DEBUG: Request to add %d pages to SG list", pages);
		vma = buf;
	}

	for (i = 0; i < pages; i++) {
		if (!buf)
			pg = vmalloc_to_page(vma + i * SAA7231_PAGE_SIZE);
		else
			pg = virt_to_page(vma + i * SAA7231_PAGE_SIZE);

		BUG_ON(!pg);

		sg_set_page(&sg_list[i], pg, SAA7231_PAGE_SIZE, 0);
	}
	dmabuf->sg_list	= sg_list;
	dmabuf->virt	= vma;
	dmabuf->vmalloc	= mem;
	dmabuf->pages	= pages; /* scatterlist length */

	return 0;
}

/* Allocates a DMA buffer for the specified external linear buffer. */
int saa7231_dmabuf_alloc(struct saa7231_dev *saa7231,
			 struct saa7231_dmabuf *dmabuf,
			 int size)
{
	struct pci_dev *pdev	= saa7231->pdev;

	int ret;

	BUG_ON(!saa7231);
	BUG_ON(!dmabuf);
	BUG_ON(! (size > 0));

	dmabuf->dma_type = SAA7231_DMABUF_INT;

	dmabuf->vmalloc	 = NULL;
	dmabuf->virt	 = NULL;
	dmabuf->pt_phys	 = 0;
	dmabuf->pt_virt	 = NULL;

	dmabuf->pages	 = 0;
	dmabuf->saa7231	 = saa7231;

	/* Allocate page table */
	ret = saa7231_allocate_ptable(dmabuf);
	if (ret) {
		dprintk(SAA7231_ERROR, 1, "PT alloc failed, Out of memory");
		goto err1;
	}

	/* Allocate buffer as SG */
	ret = saa7231_dmabuf_sgalloc(dmabuf, NULL, size);
	if (ret) {
		/* size is in pages */
		dprintk(SAA7231_ERROR, 1, "Request FAILED! for Virtual contiguous %d
byte region with %d %dk pages",
			size * SAA7231_PAGE_SIZE,
			size,
			(SAA7231_PAGE_SIZE / 1024));
		goto err2;
	}

	ret = dma_map_sg(&pdev->dev,
			 dmabuf->sg_list,
			 dmabuf->pages,
			 DMA_FROM_DEVICE);

	if (ret < 0) {
		dprintk(SAA7231_ERROR, 1, "SG map failed, ret=%d", ret);
		goto err3;
	}

	saa7231_dmabuf_sgpagefill(dmabuf, dmabuf->sg_list, ret, 0);

	return 0;
err3:
	saa7231_dmabuf_sgfree(dmabuf);
err2:
	saa7231_free_ptable(dmabuf);
err1:
	return ret;
}

/*  Fill the "page table" page with the pointers to the specified SG buffer */
static void saa7231_dmabuf_sgpagefill(struct saa7231_dmabuf *dmabuf,
				      struct scatterlist *sg_list,
				      int pages,
				      int offset)
{
	struct saa7231_dev *saa7231	= dmabuf->saa7231;
	struct pci_dev *pdev		= saa7231->pdev;
	struct scatterlist *sg_cur;

	u32 *page;
	int i, j, k = 0;
	dma_addr_t addr = 0;

	BUG_ON(!dmabuf);
	BUG_ON(!sg_list);
	BUG_ON(!pages);

	/* make page writable for the PC */
	dma_sync_single_for_cpu(&pdev->dev,
				dmabuf->pt_phys,
				SAA7231_PAGE_SIZE,
				DMA_FROM_DEVICE);

	page = dmabuf->pt_virt;

	/* create page table */
	for (i = 0; i < pages; i++) {
		sg_cur = &sg_list[i];

//		BUG_ON(!((sg_cur->length + sg_cur->offset) % SAA7231_PAGE_SIZE));

		if (i == 0)
			dmabuf->offset = (sg_cur->length + sg_cur->offset) % SAA7231_PAGE_SIZE;
		else
			BUG_ON(sg_cur->offset != 0);

		for (j = 0; (j * SAA7231_PAGE_SIZE) < sg_dma_len(sg_cur); j++) {

			if ((offset + sg_cur->offset) >= SAA7231_PAGE_SIZE) {
				offset -= SAA7231_PAGE_SIZE;
				continue;
			}

			addr = ((u64 )sg_dma_address(sg_cur)) + (j * SAA7231_PAGE_SIZE) -
sg_cur->offset;

			BUG_ON(!addr);

			if (!(i % 8) && !(i == 0))
				dprintk(SAA7231_DEBUG, 0, "\n    ");
			if ((i % 4) == 0)
				dprintk(SAA7231_DEBUG, 0, "  ");
			if (i == 0)
				dprintk(SAA7231_DEBUG, 0, "    ");

			dprintk(SAA7231_DEBUG, 0, "%04x ", addr);

			page[k * 2 + 0] = ADDR_LSB(addr); /* Low */
			page[k * 2 + 1] = ADDR_MSB(addr); /* High */

			BUG_ON(page[k * 2] % SAA7231_PAGE_SIZE);
			k++;
		}
	}

	for (; k < (SAA7231_PAGE_SIZE / 8); k++) {
		page[k * 2 + 0] = ADDR_LSB(addr);
		page[k * 2 + 1] = ADDR_MSB(addr);
	}

	/* make "page table" page writable for the PC */
	dma_sync_single_for_device(&pdev->dev,
				   dmabuf->pt_phys,
				   SAA7231_PAGE_SIZE,
				   DMA_FROM_DEVICE);

}

testbox ~ # arecord -D plughw:2,0 --format S16_LE --rate=32000 -c 2 >
~/test_capture.wav
Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 32000 Hz, Stereo
arecord: pcm_read:1617: read error: Input/output error


[  103.349513] SAA7231 0000:05:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[  103.349521] SAA7231 0000:05:00.0: setting latency timer to 64
[  103.349544] saa7231_pci_init (0): BAR 0 Offset: 04 BAR 2 Offset: 04
[  103.349547] saa7231_pci_init (0): BAR0 Start=fc800000 length=4M
[  103.349549] saa7231_pci_init (0): BAR2 Start=fc400000 length=4M
[  103.351180]     SAA7231GE [14c7:3595], irq: 16,
[  103.351183]     mmio(0): 0xf8780000 mmio(2): 0xf8c00000
[  103.351197]     SAA7231 64Bit, MSI Disabled, MSI-X=1 msgs
[  103.351203] saa7231_get_version (0): SAA7231 PCI Express V1A found
[  103.351205] saa7231_cgu_init (0): Initializing CGU
[  103.351207] saa7231_cgu_init (0): Using 54MHz RootClock
[  103.351228] saa7231_cgu_init (0): PLL Status CDEC160: 00 REF550: 00
ADPLL: 00 DSP: 00
[  103.351231] saa7231_set_clk (0): clk_output=0   clk_frequency=2
[  103.351232] saa7231_set_clk (0): clk_output=1   clk_frequency=2
[  103.351234] saa7231_set_clk (0): clk_output=2   clk_frequency=2
[  103.351236] saa7231_set_clk (0): clk_output=3   clk_frequency=2
[  103.351238] saa7231_set_clk (0): clk_output=4   clk_frequency=2
[  103.351239] saa7231_set_clk (0): clk_output=5   clk_frequency=2
[  103.351241] saa7231_set_clk (0): clk_output=6   clk_frequency=2
[  103.351243] saa7231_set_clk (0): clk_output=7   clk_frequency=2
[  103.351244] saa7231_set_clk (0): clk_output=8   clk_frequency=2
[  103.351246] saa7231_set_clk (0): clk_output=9   clk_frequency=2
[  103.351248] saa7231_set_clk (0): clk_output=10   clk_frequency=2
[  103.351250] saa7231_set_clk (0): clk_output=11   clk_frequency=2
[  103.351251] saa7231_set_clk (0): clk_output=12   clk_frequency=2
[  103.351253] saa7231_set_clk (0): clk_output=13   clk_frequency=2
[  103.351255] saa7231_set_clk (0): clk_output=14   clk_frequency=2
[  103.351257] saa7231_set_clk (0): clk_output=15   clk_frequency=2
[  103.351259] saa7231_set_clk (0): clk_output=16   clk_frequency=2
[  103.351260] saa7231_set_clk (0): clk_output=17   clk_frequency=2
[  103.351262] saa7231_set_clk (0): clk_output=18   clk_frequency=2
[  103.402026] saa7231_cgu_init (0): DEBUG: RGU_RESET_ACTIVE0 7c02001f
[  103.504025] saa7231_cgu_init (0): DEBUG: RGU_RESET_ACTIVE0 ffffffff
[  103.504029] saa7231_cgu_init (0): DEBUG: RGU_RESET_ACTIVE1 2e1f
[  103.504031] saa7231_set_clk (0): clk_output=17   clk_frequency=0
[  103.510052] saa7231_i2c_init (0): Initializing SAA7231 I2C Core
[  103.510056] saa7231_i2c_init (0): Initializing adapter (0) SAA7231 I2C:0
[  103.510254] saa7231_i2c_hwinit (0): Adapter (109000) SAA7231 I2C:0 RESET
[  103.510256] saa7231_i2c_hwinit (0): Initializing Adapter SAA7231 I2C:0 @ 100k
[  103.510264] saa7231_i2c_init (0): Initializing adapter (1) SAA7231 12C:1
[  103.510526] saa7231_i2c_hwinit (0): Adapter (10a000) SAA7231 12C:1 RESET
[  103.510528] saa7231_i2c_hwinit (0): Initializing Adapter SAA7231 12C:1 @ 100k
[  103.510536] saa7231_i2c_init (0): Initializing adapter (2) SAA7231 I2C:2
[  103.510727] saa7231_i2c_hwinit (0): Adapter (10b000) SAA7231 I2C:2 RESET
[  103.510730] saa7231_i2c_hwinit (0): Initializing Adapter SAA7231 I2C:2 @ 100k
[  103.510738] saa7231_i2c_init (0): Initializing adapter (3) SAA7231 I2C:3
[  103.510872] saa7231_i2c_hwinit (0): Adapter (10c000) SAA7231 I2C:3 RESET
[  103.510874] saa7231_i2c_hwinit (0): Initializing Adapter SAA7231 I2C:3 @ 100k
[  103.510882] saa7231_i2c_init (0): SAA7231 I2C Core succesfully initialized
[  103.510884] saa7231_alsa_init (0): Initializing Audio ..
[  103.518765] saa7231_pci_probe (0): SAA7231 device:0 initialized
[  122.183642] saa7231_capture_open (0): ()
[  122.184422] saa7231_hw_params (0): DEBUG: ()
[  122.184425] saa7231_hw_params (0): bufsiz=131072 periods=8
bytes=16384 pages=32
[  122.184428] saa7231_stream_init (0): DEBUG: Initializing Stream
with MODE=0x01
[  122.184430] saa7231_xs2dtl_init (0): XS2DTL engine Initializing .....
[  122.184433] saa7231_xs2dtl_init (0): Allocated 8 XS2DTL Buffer @0xf52d3200
[  122.184435] saa7231_xs2dtl_init (0): Allocating DMA Buffers ...
[  122.184437] saa7231_xs2dtl_init (0): Allocating DMA buffer:0 @0xf52d3200..
[  122.184447] saa7231_allocate_ptable (0): Virtual 0xf53f5000 to Phys
0x353f5000 mapped page
[  122.184464] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184487]       6c2f1000 6c277000 6c292000 6c377000
[  122.184493] saa7231_xs2dtl_init (0): Allocating DMA buffer:1 @0xf52d3228..
[  122.184501] saa7231_allocate_ptable (0): Virtual 0xf53e7000 to Phys
0x353e7000 mapped page
[  122.184507] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184527]       6c49f000 6c28d000 6c31b000 6c2e8000
[  122.184532] saa7231_xs2dtl_init (0): Allocating DMA buffer:2 @0xf52d3250..
[  122.184539] saa7231_allocate_ptable (0): Virtual 0xf4014000 to Phys
0x34014000 mapped page
[  122.184545] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184564]       6c480000 6c481000 6c31c000 6c31d000
[  122.184569] saa7231_xs2dtl_init (0): Allocating DMA buffer:3 @0xf52d3278..
[  122.184577] saa7231_allocate_ptable (0): Virtual 0xf42bb000 to Phys
0x342bb000 mapped page
[  122.184582] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184602]       6c31f000 6c2f8000 6c2f9000 6c2fa000
[  122.184606] saa7231_xs2dtl_init (0): Allocating DMA buffer:4 @0xf52d32a0..
[  122.184614] saa7231_allocate_ptable (0): Virtual 0xf42ba000 to Phys
0x342ba000 mapped page
[  122.184622] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184641]       6c2fc000 6c2fd000 6c2fe000 6c2ff000
[  122.184646] saa7231_xs2dtl_init (0): Allocating DMA buffer:5 @0xf52d32c8..
[  122.184654] saa7231_allocate_ptable (0): Virtual 0xf42b9000 to Phys
0x342b9000 mapped page
[  122.184659] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184678]       6c301000 6c302000 6c303000 6c304000
[  122.184683] saa7231_xs2dtl_init (0): Allocating DMA buffer:6 @0xf52d32f0..
[  122.184690] saa7231_allocate_ptable (0): Virtual 0xf42b8000 to Phys
0x342b8000 mapped page
[  122.184695] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184714]       6c306000 6c307000 6c308000 6c309000
[  122.184719] saa7231_xs2dtl_init (0): Allocating DMA buffer:7 @0xf52d3318..
[  122.184726] saa7231_allocate_ptable (0): Virtual 0xf42b7000 to Phys
0x342b7000 mapped page
[  122.184732] saa7231_dmabuf_sgalloc (0): Virtual contiguous 16384
byte region with 4 4k pages
[  122.184751]       6c30b000 6c30c000 6c30d000 6c30e000
[  122.184756] saa7231_xs2dtl_init (0): Initializing PTA ...
[  122.184758] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[  122.184760] saa7231_xs2dtl_init (0): Setting up PORT Gates ...
[  122.184762] saa7231_stream_init (0): INFO: Initialized MODE:0x01 for PORT:6
[  122.184765] saa7231_add_irqevent (0): Adding AS2D_AVIS IRQ Event:43 ...
[  122.184767] saa7231_setup_vector (0): Adding Vector:43
[  122.184771] saa7231_setup_vector (0): Enabling Vector:43
[  122.184775] saa7231_add_irqevent (0): Succesfully added AS2D_AVIS
as Event handler:43
[  122.184777] saa7231_hw_params (0): Mapping 8 buffers with 4 pages each
[  122.184778] saa7231_hw_params (0): Page Table array size=1
[  122.184780] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:0 to PTA Offset:0
[  122.184782] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:0 to PTA Offset:1
[  122.184784] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:0 to PTA Offset:2
[  122.184786] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:0 to PTA Offset:3
[  122.184788] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:1 to PTA Offset:4
[  122.184790] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:1 to PTA Offset:5
[  122.184791] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:1 to PTA Offset:6
[  122.184793] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:1 to PTA Offset:7
[  122.184795] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:2 to PTA Offset:8
[  122.184797] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:2 to PTA Offset:9
[  122.184799] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:2 to PTA Offset:10
[  122.184801] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:2 to PTA Offset:11
[  122.184803] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:3 to PTA Offset:12
[  122.184805] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:3 to PTA Offset:13
[  122.184807] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:3 to PTA Offset:14
[  122.184809] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:3 to PTA Offset:15
[  122.184810] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:4 to PTA Offset:16
[  122.184812] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:4 to PTA Offset:17
[  122.184814] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:4 to PTA Offset:18
[  122.184816] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:4 to PTA Offset:19
[  122.184818] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:5 to PTA Offset:20
[  122.184820] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:5 to PTA Offset:21
[  122.184822] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:5 to PTA Offset:22
[  122.184824] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:5 to PTA Offset:23
[  122.184826] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:6 to PTA Offset:24
[  122.184828] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:6 to PTA Offset:25
[  122.184830] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:6 to PTA Offset:26
[  122.184832] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:6 to PTA Offset:27
[  122.184834] saa7231_hw_params (0): Mapping Page:0 from
XS2D_BUFFER:7 to PTA Offset:28
[  122.184835] saa7231_hw_params (0): Mapping Page:1 from
XS2D_BUFFER:7 to PTA Offset:29
[  122.184837] saa7231_hw_params (0): Mapping Page:2 from
XS2D_BUFFER:7 to PTA Offset:30
[  122.184839] saa7231_hw_params (0): Mapping Page:3 from
XS2D_BUFFER:7 to PTA Offset:31
[  122.184864] saa7231_capture_prepare (0): ()
[  122.184866] saa7231_capture_prepare (0): Trying to Acquire stream
with 4096lines per stream buffer
[  122.184868] saa7231_xs2dtl_acquire (0): Activating clock ..
mode=0x01, port_id=0x06
[  122.184871] saa7231_activate_clocks (0): DEBUG: Activating Clock
for Mode=0x01, port=0x06
[  122.184873] tmGetClockInstance (0): DEBUG: Mode=0x01, dmaport=0x06
[  122.184875] tmGetClockInstance (0): ret=0
[  122.184880] saa7231_activate_clocks (0): INFO: activate use case index 0
[  122.184882] saa7231_init_ptables (0): DEBUG: Initializing PORT:6
DMA_CH:7 with 8 Buffers
[  122.190510] saa7231_capture_trigger (0): Tring to START stream, cmd=1
[  122.201045]
[  122.201047] =================================
[  122.201050] [ INFO: inconsistent lock state ]
[  122.201052] 2.6.34.7 #2
[  122.201053] ---------------------------------
[  122.201055] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
[  122.201058] arecord/5860 [HC0[0]:SC0[0]:HE1:SE1] takes:
[  122.201060]  (&(&substream->self_group.lock)->rlock){?.-...}, at:
[<c13271b5>] snd_pcm_stream_lock_irq+0x20/0x23
[  122.201068] {IN-HARDIRQ-W} state was registered at:
[  122.201069]   [<c105a27c>] __lock_acquire+0x23e/0xb47
[  122.201074]   [<c105ac11>] lock_acquire+0x8c/0xab
[  122.201077]   [<c144a8bb>] _raw_spin_lock+0x20/0x2f
[  122.201081]   [<c132811e>] snd_pcm_period_elapsed+0x39/0xb4
[  122.201084]   [<f843040f>] azx_interrupt+0x8e/0x106 [snd_hda_intel]
[  122.201090]   [<c1079a16>] handle_IRQ_event+0x4b/0xf1
[  122.201093]   [<c107b469>] handle_fasteoi_irq+0x86/0xbd
[  122.201096] irq event stamp: 4520
[  122.201098] hardirqs last  enabled at (4519): [<c100287b>]
sysenter_exit+0xf/0x16
[  122.201101] hardirqs last disabled at (4520): [<c144ac7b>]
_raw_read_lock_irq+0x11/0x35
[  122.201105] softirqs last  enabled at (3784): [<c1039b96>]
__do_softirq+0x15a/0x169
[  122.201108] softirqs last disabled at (3757): [<c10042fc>]
do_softirq+0x63/0xaf
[  122.201111]
[  122.201111] other info that might help us debug this:
[  122.201113] 2 locks held by arecord/5860:
[  122.201115]  #0:  (snd_pcm_link_rwlock){.?.-..}, at: [<c13271aa>]
snd_pcm_stream_lock_irq+0x15/0x23
[  122.201120]  #1:  (&(&substream->self_group.lock)->rlock){?.-...},
at: [<c13271b5>] snd_pcm_stream_lock_irq+0x20/0x23
[  122.201124]
[  122.201125] stack backtrace:
[  122.201127] Pid: 5860, comm: arecord Not tainted 2.6.34.7 #2
[  122.201129] Call Trace:
[  122.201132]  [<c1448b56>] ? printk+0x14/0x16
[  122.201134]  [<c105938f>] valid_state+0x12a/0x13d
[  122.201137]  [<c1059493>] mark_lock+0xf1/0x1d9
[  122.201140]  [<c1059b3c>] ? check_usage_backwards+0x0/0x68
[  122.201142]  [<c10595be>] mark_held_locks+0x43/0x5b
[  122.201145]  [<c144ad98>] ? _raw_spin_unlock_irq+0x27/0x2b
[  122.201148]  [<c10597d7>] trace_hardirqs_on_caller+0xe7/0x121
[  122.201151]  [<c105981c>] trace_hardirqs_on+0xb/0xd
[  122.201153]  [<c144ad98>] _raw_spin_unlock_irq+0x27/0x2b
[  122.201157]  [<c102d6ac>] finish_task_switch+0x5c/0x86
[  122.201160]  [<c102d650>] ? finish_task_switch+0x0/0x86
[  122.201162]  [<c144925d>] schedule+0x53d/0x5b4
[  122.201165]  [<c14495ec>] schedule_timeout+0x7e/0x9b
[  122.201169]  [<c103f3ea>] ? process_timeout+0x0/0xf
[  122.201172]  [<c1449623>] schedule_timeout_uninterruptible+0x1a/0x1c
[  122.201175]  [<c103f8e9>] msleep+0x15/0x1b
[  122.201183]  [<f83b5974>] saa7231_xs2dtl_run+0x93/0x123 [saa7231_core]
[  122.201190]  [<f83b9749>] saa7231_capture_trigger+0x5c/0x158 [saa7231_core]
[  122.201193]  [<c13226e3>] snd_pcm_do_start+0x23/0x26
[  122.201196]  [<c132263a>] snd_pcm_action_single+0x2a/0x50
[  122.201199]  [<c1323ce8>] snd_pcm_action+0x6f/0x7b
[  122.201202]  [<c1323d8a>] snd_pcm_start+0x19/0x1b
[  122.201204]  [<c13283a0>] snd_pcm_lib_read1+0x61/0x1ff
[  122.201207]  [<c13285be>] snd_pcm_lib_read+0x33/0x54
[  122.201210]  [<c13273e5>] ? snd_pcm_lib_read_transfer+0x0/0x70
[  122.201213]  [<c1325ec1>] snd_pcm_capture_ioctl1+0x8e/0x2ed
[  122.201215]  [<c1326148>] snd_pcm_capture_ioctl+0x28/0x35
[  122.201219]  [<c10c7ec5>] vfs_ioctl+0x2c/0x96
[  122.201222]  [<c1326120>] ? snd_pcm_capture_ioctl+0x0/0x35
[  122.201224]  [<c10c843f>] do_vfs_ioctl+0x46c/0x4aa
[  122.201228]  [<c10bd0f3>] ? fsnotify_modify+0x54/0x5f
[  122.201231]  [<c10bd1fe>] ? do_sync_write+0x0/0xca
[  122.201234]  [<c10be3e3>] ? fget_light+0xe/0xaf
[  122.201236]  [<c10c84b0>] sys_ioctl+0x33/0x4d
[  122.201239]  [<c100284c>] sysenter_do_call+0x12/0x32
[  133.191022] saa7231_xs2dtl_run (0): ERROR, Preload PTA failed
[  133.191027] saa7231_capture_trigger (0): ERROR: starting stream, err=-22
[  133.191030] saa7231_capture_trigger (0): Tring to STOP stream, cmd=0
[  133.191179] saa7231_hw_free (0): DEBUG: Removing IRQ event ..
[  133.191195] saa7231_remove_irqevent (0): Removing IRQ Event:43 ......
[  133.191225] saa7231_remove_irqevent (0): IRQ Event 43 <AS2D_AVIS> removed
[  133.191229] saa7231_hw_free (0): DEBUG: Unmap Virtual memory region ..
[  133.191241] saa7231_hw_free (0): DEBUG: Stream exiting ..
[  133.191244] saa7231_stream_exit (0): INFO: Freeing MODE:0x01 for PORT=0x06
[  133.191247] saa7231_xs2dtl_exit (0): Free XS2DTL engine ..
[  133.191249] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191253] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191255] saa7231_dmabuf_sgfree (0): SG free
[  133.191261] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191263] saa7231_free_ptable (0): SG Page table free
[  133.191267] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191271] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191273] saa7231_dmabuf_sgfree (0): SG free
[  133.191278] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191280] saa7231_free_ptable (0): SG Page table free
[  133.191284] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191288] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191289] saa7231_dmabuf_sgfree (0): SG free
[  133.191295] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191296] saa7231_free_ptable (0): SG Page table free
[  133.191300] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191304] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191305] saa7231_dmabuf_sgfree (0): SG free
[  133.191311] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191313] saa7231_free_ptable (0): SG Page table free
[  133.191316] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191320] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191322] saa7231_dmabuf_sgfree (0): SG free
[  133.191327] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191329] saa7231_free_ptable (0): SG Page table free
[  133.191332] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191336] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191338] saa7231_dmabuf_sgfree (0): SG free
[  133.191343] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191345] saa7231_free_ptable (0): SG Page table free
[  133.191348] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191351] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191352] saa7231_dmabuf_sgfree (0): SG free
[  133.191359] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191361] saa7231_free_ptable (0): SG Page table free
[  133.191364] saa7231_dmabuf_free (0): INFO: Scatterlist unmapped
[  133.191367] saa7231_dmabuf_free (0): INFO: Scatterlist free
[  133.191369] saa7231_dmabuf_sgfree (0): SG free
[  133.191374] saa7231_dmabuf_free (0): INFO: Page table free
[  133.191377] saa7231_free_ptable (0): SG Page table free
[  133.191381] saa7231_hw_free (0): DEBUG: Freeing ptable ...
[  133.191383] saa7231_capture_close (0): DEBUG: Closing stream


More information about the Alsa-devel mailing list