Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc02d50a authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (5675): Move big PIO accesses from the interrupt handler to a workhandler



Sliced VBI transfers use PIO instead of DMA. This was done inside the
interrupt handler, but since PIO accesses are very slow this meant that
a lot of time was spent inside the interrupt handler. All PIO copies are
now moved to a workqueue. This should fix various issues with missing time
ticks and remote key hits.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent ffeb9ec7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -652,6 +652,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
	itv->dma_timer.data = (unsigned long)itv;

	itv->cur_dma_stream = -1;
	itv->cur_pio_stream = -1;
	itv->audio_stereo_mode = AUDIO_STEREO;
	itv->audio_bilingual_mode = AUDIO_MONO_LEFT;

+13 −3
Original line number Diff line number Diff line
@@ -237,6 +237,7 @@ extern const u32 yuv_offset[4];
#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
#define IVTV_IRQ_ENC_PIO_COMPLETE	(0x1 << 25)
#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
@@ -247,7 +248,8 @@ extern const u32 yuv_offset[4];
#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)

/* IRQ Masks */
#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|IVTV_IRQ_DMA_READ)
#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
		IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)

#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
#define IVTV_IRQ_MASK_DECODE  (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
@@ -374,6 +376,9 @@ struct ivtv_mailbox_data {
#define IVTV_F_S_STREAMOFF	7	/* signal end of stream EOS */
#define IVTV_F_S_APPL_IO        8	/* this stream is used read/written by an application */

#define IVTV_F_S_PIO_PENDING	9	/* this stream has pending PIO */
#define IVTV_F_S_PIO_HAS_VBI	1       /* the current PIO request also requests VBI data */

/* per-ivtv, i_flags */
#define IVTV_F_I_DMA		   0 	/* DMA in progress */
#define IVTV_F_I_UDMA		   1 	/* UDMA in progress */
@@ -390,8 +395,11 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DECODING_YUV	   12 	/* this stream is YUV frame decoding */
#define IVTV_F_I_ENC_PAUSED	   13 	/* the encoder is paused */
#define IVTV_F_I_VALID_DEC_TIMINGS 14 	/* last_dec_timing is valid */
#define IVTV_F_I_WORK_HANDLER_VBI  15	/* there is work to be done for VBI */
#define IVTV_F_I_WORK_HANDLER_YUV  16	/* there is work to be done for YUV */
#define IVTV_F_I_HAVE_WORK  	   15	/* Used in the interrupt handler: there is work to be done */
#define IVTV_F_I_WORK_HANDLER_VBI  16	/* there is work to be done for VBI */
#define IVTV_F_I_WORK_HANDLER_YUV  17	/* there is work to be done for YUV */
#define IVTV_F_I_WORK_HANDLER_PIO  18	/* there is work to be done for PIO */
#define IVTV_F_I_PIO		   19	/* PIO in progress */

/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
@@ -484,6 +492,7 @@ struct ivtv_stream {

	/* Base Dev SG Array for cx23415/6 */
	struct ivtv_SG_element *SGarray;
	struct ivtv_SG_element *PIOarray;
	dma_addr_t SG_handle;
	int SG_length;

@@ -706,6 +715,7 @@ struct ivtv {
	atomic_t decoding;	/* count number of active decoding streams */
	u32 irq_rr_idx; /* Round-robin stream index */
	int cur_dma_stream;	/* index of stream doing DMA */
	int cur_pio_stream;	/* index of stream doing PIO */
	u32 dma_data_req_offset;
	u32 dma_data_req_size;
	int output_mode;        /* NONE, MPG, YUV, UDMA YUV, passthrough */
+137 −67
Original line number Diff line number Diff line
@@ -31,8 +31,6 @@

#define DMA_MAGIC_COOKIE 0x000001fe

#define SLICED_VBI_PIO 1

static void ivtv_dma_dec_start(struct ivtv_stream *s);

static const int ivtv_stream_map[] = {
@@ -42,12 +40,40 @@ static const int ivtv_stream_map[] = {
	IVTV_ENC_STREAM_TYPE_VBI,
};

static inline int ivtv_use_pio(struct ivtv_stream *s)

static void ivtv_pio_work_handler(struct ivtv *itv)
{
	struct ivtv *itv = s->itv;
	struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
	struct ivtv_buffer *buf;
	struct list_head *p;
	int i = 0;

	IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
			s->v4l2dev == NULL || !ivtv_use_pio(s)) {
		itv->cur_pio_stream = -1;
		/* trigger PIO complete user interrupt */
		write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
		return;
	}
	IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
	buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
	list_for_each(p, &s->q_dma.list) {
		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
		u32 size = s->PIOarray[i].size & 0x3ffff;

	return s->dma == PCI_DMA_NONE ||
	    (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set);
		/* Copy the data from the card to the buffer */
		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
			memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size);
		}
		else {
			memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size);
		}
		if (s->PIOarray[i].size & 0x80000000)
			break;
		i++;
	}
	write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}

void ivtv_irq_work_handler(struct work_struct *work)
@@ -56,8 +82,11 @@ void ivtv_irq_work_handler(struct work_struct *work)

	DEFINE_WAIT(wait);

	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
		ivtv_pio_work_handler(itv);

	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
		vbi_work_handler(itv);
		ivtv_vbi_work_handler(itv);

	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
		ivtv_yuv_work_handler(itv);
@@ -173,8 +202,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
	}
	s->buffers_stolen = rc;

	/* got the buffers, now fill in SGarray (DMA) or copy the data from the card
	   to the buffers (PIO). */
	/* got the buffers, now fill in SGarray (DMA) */
	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
	memset(buf->buf, 0, 128);
	list_for_each(p, &s->q_predma.list) {
@@ -182,21 +210,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA

		if (skip_bufs-- > 0)
			continue;
		if (!ivtv_use_pio(s)) {
		s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle);
		s->SGarray[idx].src = cpu_to_le32(offset);
		s->SGarray[idx].size = cpu_to_le32(s->buf_size);
		}
		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;

		/* If PIO, then copy the data from the card to the buffer */
		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
			memcpy_fromio(buf->buf, itv->dec_mem + offset - IVTV_DECODER_OFFSET, buf->bytesused);
		}
		else if (ivtv_use_pio(s)) {
			memcpy_fromio(buf->buf, itv->enc_mem + offset, buf->bytesused);
		}

		s->q_predma.bytesused += buf->bytesused;
		size -= buf->bytesused;
		offset += s->buf_size;
@@ -224,11 +242,6 @@ static void dma_post(struct ivtv_stream *s)
	u32 *u32buf;
	int x = 0;

	if (ivtv_use_pio(s)) {
		if (s->q_predma.bytesused)
			ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
		s->SG_length = 0;
	}
	IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
			s->name, s->dma_offset);
	list_for_each(p, &s->q_dma.list) {
@@ -278,10 +291,14 @@ static void dma_post(struct ivtv_stream *s)
	if (buf)
		buf->bytesused += s->dma_last_offset;
	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
		list_for_each(p, &s->q_dma.list) {
			buf = list_entry(p, struct ivtv_buffer, list);

			/* Parse and Groom VBI Data */
			s->q_dma.bytesused -= buf->bytesused;
			ivtv_process_vbi_data(itv, buf, 0, s->type);
			s->q_dma.bytesused += buf->bytesused;
		}
		if (s->id == -1) {
			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
			return;
@@ -351,10 +368,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
	int i;

	IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);

	if (s->q_predma.bytesused)
		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
	IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
	s->SGarray[s->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);

	if (ivtv_use_dma(s))
		s->SGarray[s->SG_length - 1].size =
			cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);

	/* If this is an MPEG stream, and VBI data is also pending, then append the
	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
@@ -368,6 +389,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length &&
			s->SG_length + s_vbi->SG_length <= s->buffers) {
		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
		if (ivtv_use_dma(s_vbi))
			s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256);
		for (i = 0; i < s_vbi->SG_length; i++) {
			s->SGarray[s->SG_length++] = s_vbi->SGarray[i];
@@ -381,6 +403,17 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
	/* Mark last buffer size for Interrupt flag */
	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);

	if (ivtv_use_pio(s)) {
		for (i = 0; i < s->SG_length; i++) {
			s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
			s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size);
		}
		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
		set_bit(IVTV_F_I_PIO, &itv->i_flags);
		itv->cur_pio_stream = s->type;
	}
	else {
		/* Sync Hardware SG List of buffers */
		ivtv_stream_sync_for_device(s);
		write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR);
@@ -390,6 +423,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
		itv->dma_timer.expires = jiffies + HZ / 10;
		add_timer(&itv->dma_timer);
	}
}

static void ivtv_dma_dec_start(struct ivtv_stream *s)
{
@@ -489,6 +523,40 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
	wake_up(&itv->dma_waitq);
}

static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
{
	struct ivtv_stream *s;

	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) {
		itv->cur_pio_stream = -1;
		return;
	}
	s = &itv->streams[itv->cur_pio_stream];
	IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
	s->SG_length = 0;
	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
	itv->cur_pio_stream = -1;
	dma_post(s);
	if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0);
	else if (s->type == IVTV_ENC_STREAM_TYPE_YUV)
		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1);
	else if (s->type == IVTV_ENC_STREAM_TYPE_PCM)
		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
		u32 tmp;

		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
		tmp = s->dma_offset;
		s->dma_offset = itv->vbi.dma_offset;
		dma_post(s);
		s->dma_offset = tmp;
	}
	wake_up(&itv->dma_waitq);
}

static void ivtv_irq_dma_err(struct ivtv *itv)
{
	u32 data[CX2341X_MBOX_MAX_DATA];
@@ -532,13 +600,7 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
	s = &itv->streams[ivtv_stream_map[data[0]]];
	if (!stream_enc_dma_append(s, data)) {
		if (ivtv_use_pio(s)) {
			dma_post(s);
			ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[0]);
		}
		else {
			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
		}
		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
	}
}

@@ -551,15 +613,6 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
	IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];

	if (ivtv_use_pio(s)) {
		if (stream_enc_dma_append(s, data))
			return;
		if (s->q_predma.bytesused)
			ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
		s->SG_length = 0;
		dma_post(s);
		return;
	}
	/* If more than two VBI buffers are pending, then
	   clear the old ones and start with this new one.
	   This can happen during transition stages when MPEG capturing is
@@ -582,11 +635,11 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
	if (!stream_enc_dma_append(s, data) &&
			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
		set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
		set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
	}
}

static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv)
static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
{
	u32 data[CX2341X_MBOX_MAX_DATA];
	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
@@ -594,7 +647,7 @@ static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv)
	IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
			!stream_enc_dma_append(s, data)) {
		dma_post(s);
		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
	}
}

@@ -657,7 +710,6 @@ static void ivtv_irq_vsync(struct ivtv *itv)
	}
	if (frame != (itv->lastVsyncFrame & 1)) {
		struct ivtv_stream *s = ivtv_get_output_stream(itv);
		int work = 0;

		itv->lastVsyncFrame += 1;
		if (frame == 0) {
@@ -678,7 +730,7 @@ static void ivtv_irq_vsync(struct ivtv *itv)
		/* Send VBI to saa7127 */
		if (frame) {
			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
			work = 1;
			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
		}

		/* Check if we need to update the yuv registers */
@@ -691,11 +743,9 @@ static void ivtv_irq_vsync(struct ivtv *itv)
				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
				itv->yuv_info.yuv_forced_update = 0;
				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
				work = 1;
				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
			}
		}
		if (work)
			queue_work(itv->irq_work_queues, &itv->irq_work_queue);
	}
}

@@ -755,6 +805,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
		ivtv_irq_enc_dma_complete(itv);
	}

	if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) {
		ivtv_irq_enc_pio_complete(itv);
	}

	if (combo & IVTV_IRQ_DMA_ERR) {
		ivtv_irq_dma_err(itv);
	}
@@ -768,7 +822,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
	}

	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
		ivtv_irq_dev_vbi_reinsert(itv);
		ivtv_irq_dec_vbi_reinsert(itv);
	}

	if (combo & IVTV_IRQ_ENC_EOS) {
@@ -813,6 +867,22 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
		}
	}

	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
			int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
			struct ivtv_stream *s = &itv->streams[idx];

			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
				continue;
			if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG)
				ivtv_dma_enc_start(s);
			break;
		}
	}

	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags))
		queue_work(itv->irq_work_queues, &itv->irq_work_queue);

	spin_unlock(&itv->dma_reg_lock);

	/* If we've just handled a 'forced' vsync, it's safest to say it
+23 −8
Original line number Diff line number Diff line
@@ -195,14 +195,26 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
		s->dma != PCI_DMA_NONE ? "DMA " : "",
		s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);

	if (ivtv_might_use_pio(s)) {
		s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
		if (s->PIOarray == NULL) {
			IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
			return -ENOMEM;
		}
	}

	/* Allocate DMA SG Arrays */
	if (s->dma != PCI_DMA_NONE) {
	s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
	if (s->SGarray == NULL) {
		IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
		if (ivtv_might_use_pio(s)) {
			kfree(s->PIOarray);
			s->PIOarray = NULL;
		}
		return -ENOMEM;
	}
	s->SG_length = 0;
	if (ivtv_might_use_dma(s)) {
		s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
		ivtv_stream_sync_for_cpu(s);
	}
@@ -219,7 +231,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
			break;
		}
		INIT_LIST_HEAD(&buf->list);
		if (s->dma != PCI_DMA_NONE) {
		if (ivtv_might_use_dma(s)) {
			buf->dma_handle = pci_map_single(s->itv->dev,
				buf->buf, s->buf_size + 256, s->dma);
			ivtv_buf_sync_for_cpu(s, buf);
@@ -242,7 +254,7 @@ void ivtv_stream_free(struct ivtv_stream *s)

	/* empty q_free */
	while ((buf = ivtv_dequeue(s, &s->q_free))) {
		if (s->dma != PCI_DMA_NONE)
		if (ivtv_might_use_dma(s))
			pci_unmap_single(s->itv->dev, buf->dma_handle,
				s->buf_size + 256, s->dma);
		kfree(buf->buf);
@@ -256,6 +268,9 @@ void ivtv_stream_free(struct ivtv_stream *s)
				 sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
			s->SG_handle = IVTV_DMA_UNMAPPED;
		}
		kfree(s->SGarray);
		kfree(s->PIOarray);
		s->PIOarray = NULL;
		s->SGarray = NULL;
		s->SG_length = 0;
	}
+33 −6
Original line number Diff line number Diff line
@@ -20,18 +20,43 @@
 */

#define IVTV_DMA_UNMAPPED	((u32) -1)
#define SLICED_VBI_PIO 1

/* ivtv_buffer utility functions */

static inline int ivtv_might_use_pio(struct ivtv_stream *s)
{
	return s->dma == PCI_DMA_NONE || (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI);
}

static inline int ivtv_use_pio(struct ivtv_stream *s)
{
	struct ivtv *itv = s->itv;

	return s->dma == PCI_DMA_NONE ||
	    (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set);
}

static inline int ivtv_might_use_dma(struct ivtv_stream *s)
{
	return s->dma != PCI_DMA_NONE;
}

static inline int ivtv_use_dma(struct ivtv_stream *s)
{
	return !ivtv_use_pio(s);
}

static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
{
	if (s->dma != PCI_DMA_NONE)
	if (ivtv_use_dma(s))
		pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle,
				s->buf_size + 256, s->dma);
}

static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
{
	if (s->dma != PCI_DMA_NONE)
	if (ivtv_use_dma(s))
		pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle,
				s->buf_size + 256, s->dma);
}
@@ -53,12 +78,14 @@ void ivtv_stream_free(struct ivtv_stream *s);

static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
{
	if (ivtv_use_dma(s))
		pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle,
			sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
}

static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
{
	if (ivtv_use_dma(s))
		pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle,
			sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
}
Loading