Petter Gundersen wrote:
> I have some info about the issue with high cpu usage while using the
> pvr350 tv-out and mythtv.
>
> Earlier reports here:
> http://www.gossamer-threads.com/lists/ivtv/users/32506#32506
> http://www.gossamer-threads.com/lists/ivtv/users/32807#32807
>
> This started happening between ivtv 0.7.0 and 0.7.1, more precisely
> changeset 3406 "Added workaround for the DMA 0x0000000b error...".
>
> I'm not sure if this is a ivtv bug, a myth bug, or if some of my
> kernel settings are messing things up. Since I never have had any
> problems with the DMA 0x0000000b error, I use the attached patch with
> ivtv 0.8.1, and my cpu usage is back to it's normal ~1%. The patch
> reverts changeset 3413, 3407 and parts of 3400.
I'll second that. I had very high CPU usage on the pvr350 too recently
(head branch 0.8 on 2.6.18), but I thought it was somehow caused by
xorg7.1, but your patch brings it back to normal.
Thanks.
Jelle.
>
> Regards,
> Petter
>
>
> ------------------------------------------------------------------------
>
> diff -ur ivtv-0.8.1.orig/driver/ivtv-driver.h ivtv-0.8.1/driver/ivtv-driver.h
> --- ivtv-0.8.1.orig/driver/ivtv-driver.h 2006-11-19 13:07:58.000000000
> +0100
> +++ ivtv-0.8.1/driver/ivtv-driver.h 2006-12-01 16:48:38.000000000 +0100
> @@ -691,8 +691,6 @@
>
> /* Buffer Stats */
> atomic_t allocated_buffers;
> - u32 buf_backup;
> - u32 last_offset;
> int buffers;
> u32 buf_min;
> int bufsize;
> diff -ur ivtv-0.8.1.orig/driver/ivtv-irq.c ivtv-0.8.1/driver/ivtv-irq.c
> --- ivtv-0.8.1.orig/driver/ivtv-irq.c 2006-09-25 11:31:57.000000000 +0200
> +++ ivtv-0.8.1/driver/ivtv-irq.c 2006-12-01 16:48:38.000000000 +0100
> @@ -29,7 +29,7 @@
>
> typedef unsigned long uintptr_t;
>
> -static void ivtv_FROM_DMA_done(struct ivtv *itv, int type, void *src);
> +static void ivtv_FROM_DMA_done(struct ivtv *itv, int type);
> static int dma_from_device(struct ivtv *itv, struct ivtv_stream *st);
>
> IRQRETURN_T ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
> @@ -70,7 +70,7 @@
>
> /* Exclude 0x400 from the output, otherwise the log is flooded with
> these messages */
> - if (combo & ~(0x88000400))
> + if (combo != 0x400)
> IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n",
> combo);
>
> if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT2) {
> @@ -101,13 +101,14 @@
> wake_up(&itv->r_intr_wq);
> }
> if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
> - //IVTV_DEBUG_IRQ("IRQ: IVTV_IRQ_ENC_DMA_COMPLETE\n");
> + IVTV_DEBUG_IRQ("IRQ: IVTV_IRQ_ENC_DMA_COMPLETE\n");
> atomic_set(&itv->w_intr, 1);
> wake_up(&itv->w_intr_wq);
> }
> if (combo & IVTV_IRQ_DMA_ERR) {
> - atomic_set(&itv->w_intr, 1);
> - wake_up(&itv->w_intr_wq);
> + IVTV_DEBUG_WARN(
> + "IRQ: IVTV_IRQ_DEC_DMA_ERR\n");
> + writel(0x0, itv->reg_mem + IVTV_REG_DMAXFER);
> }
>
> /* Define irq bits */
> @@ -120,7 +121,7 @@
>
> if (combo & IVTV_IRQ_ENC_DMA) {
> if (combo & IVTV_IRQ_ENC_START_CAP) {
> - //IVTV_DEBUG_IRQ("IRQ ENC DMA\n");
> + IVTV_DEBUG_IRQ("IRQ ENC DMA\n");
>
> /* set dma needed flag */
> set_bit(IVTV_F_T_ENC_DMA_NEEDED, &itv->t_flags);
> @@ -267,13 +268,11 @@
> return IRQ_HANDLED;
> }
>
> -static void ivtv_FROM_DMA_done(struct ivtv *itv, int stmtype, void *src)
> +static void ivtv_FROM_DMA_done(struct ivtv *itv, int stmtype)
> {
> struct ivtv_stream *stream = NULL;
> struct ivtv_buffer *buf;
> int freed = 0;
> - int x = 0;
> - int offset = 0;
>
> IVTV_DEBUG_DMA("ENC: DMA Done\n");
>
> @@ -284,43 +283,13 @@
> /* Sync Buffer */
> #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 8)
> pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev,
> - buf->dma_handle, buf->buffer.length
> + 256,
> + buf->dma_handle, buf->buffer.length,
> stream->dma);
> #else
> pci_dma_sync_single(itv->dev, buf->dma_handle,
> - buf->buffer.length + 256, stream->dma);
> + buf->buffer.length, stream->dma);
> #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 8) */
>
> - if (x == 0) {
> - offset = stream->last_offset;
> - if (((u32 *)(buf->buffer.m.userptr))[offset / 4] !=
> 0x000001fe) {
> - for (offset = 0; offset < 64; offset++) {
> - if (((u32
> *)(buf->buffer.m.userptr))[offset] == 0x000001fe) {
> - break;
> - }
> - }
> - offset *= 4;
> - if (offset == 256) {
> - IVTV_DEBUG_WARN("Couldn't find start of
> buffer within the first 256 bytes\n");
> - offset = 0;
> - }
> - if (stream->last_offset != offset)
> - IVTV_DEBUG_WARN("offset %d -> %d\n",
> stream->last_offset, offset);
> - stream->last_offset = offset;
> - }
> - writel(0, src);
> - if (offset) {
> - buf->buffer.bytesused -= offset;
> - memcpy((void *)buf->buffer.m.userptr,
> - (void *)(buf->buffer.m.userptr +
> offset),
> - buf->buffer.bytesused + offset);
> - }
> - *(u32 *)(buf->buffer.m.userptr) = stream->buf_backup;
> - }
> - if (list_empty(&stream->dma_q.list)) {
> - buf->buffer.bytesused += stream->last_offset;
> - }
> - x++;
> /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
> if (stmtype == IVTV_ENC_STREAM_TYPE_MPG)
> set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags);
> @@ -360,17 +329,17 @@
> void ivtv_sched_DMA(struct ivtv *itv)
> {
> u32 data[CX2341X_MBOX_MAX_DATA], result;
> - u32 type, size, offset, streamtype;
> + u32 type, size, offset, streamtype, pad = 0;
> u32 UVsize = 0, UVoffset = 0;
> u64 pts_stamp = 0;
> struct ivtv_stream *st;
> int x;
> - void *src = (void *)itv->enc_mem;
> int uvflag = 0;
> long sequence;
> u32 bytes_needed = 0, bytes_read = 0, bytes_received = 0;
> struct ivtv_buffer *buf;
> LIST_HEAD(free_list);
> + int xfer_pad;
> unsigned long then;
> DECLARE_WAITQUEUE(wait, current);
> int rc = 0;
> @@ -433,11 +402,10 @@
> case 2: /* PCM (audio) */
> offset = data[1] + 12;
> size = data[2] - 12;
> - pts_stamp = readl(itv->dec_mem + offset - 8);
> + pts_stamp = *(u32 *) (itv->dec_mem + offset - 8);
> pts_stamp |=
> - (u64) (readl(itv->dec_mem + offset - 12)) << 32;
> + (u64) (*(u32 *) (itv->dec_mem + offset - 12)) << 32;
> offset += IVTV_DECODER_OFFSET;
> - src = (void *)(itv->dec_mem - IVTV_DECODER_OFFSET);
> IVTV_DEBUG_INFO(
> "DMA/PCM type 0x%08x,size 0x%08x,offset 0x%08x "
> "PTS 0x%09llx\n", type, size, offset, pts_stamp);
> @@ -553,9 +521,6 @@
> sequence = ++st->seq;
>
> st->ubytes = size;
> - src += offset;
> - st->buf_backup = readl(src);
> - writel(0x000001fe, src);
>
> for (x = 0; bytes_read < bytes_needed; x++) {
> /* extract the buffers we procured earlier */
> @@ -571,10 +536,18 @@
> bytes_read += buf->buffer.length;
>
> if (size < buf->buffer.length) {
> + xfer_pad = buf->buffer.length /*256 */ ;
> + pad = size;
> buf->buffer.bytesused = size;
> - st->SGarray[x].size = buf->buffer.length;
> + if (size > xfer_pad && size % xfer_pad) /* Align */
> + size = size + (size % xfer_pad);
> + if (size < xfer_pad) /* Too small */
> + size = xfer_pad;
> + st->SGarray[x].size = size;
> size = 0;
> +
> } else {
> + pad = 0;
> buf->buffer.bytesused = buf->buffer.length;
> st->SGarray[x].size = buf->buffer.length;
> size -= st->SGarray[x].size;
> @@ -594,11 +567,11 @@
> /* Sync SG buffers */
> pci_dma_sync_single_for_device((struct pci_dev *)itv->dev,
> buf->dma_handle,
> - buf->buffer.length + 256,
> st->dma);
> + buf->buffer.length, st->dma);
> #else
> /* Sync SG buffers */
> pci_dma_sync_single(itv->dev, buf->dma_handle,
> - buf->buffer.length + 256, st->dma);
> + buf->buffer.length, st->dma);
> #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 8) */
>
> ivtv_enq_buf_nolock(&st->dma_q, buf);
> @@ -611,7 +584,6 @@
> }
> }
> st->SG_length = x;
> - st->SGarray[x - 1].size += 256;
>
> /* This should wrap gracefully */
> st->trans_id++;
> @@ -642,7 +614,7 @@
> ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0,
> st->type);
>
> /* Gather Buffers from DMA xfer to read */
> - ivtv_FROM_DMA_done(itv, st->type, src);
> + ivtv_FROM_DMA_done(itv, st->type);
> } else {
> //down(&itv->DMA_lock);
> if (dma_from_device(itv, st) != 0) {
> @@ -651,7 +623,7 @@
> //up(&itv->DMA_lock);
>
> /* Gather Buffers from DMA xfer to read */
> - ivtv_FROM_DMA_done(itv, st->type, src);
> + ivtv_FROM_DMA_done(itv, st->type);
> }
>
> clear_bit(IVTV_F_S_DMAP, &st->s_flags);
> @@ -665,15 +637,14 @@
> unsigned long flags;
> int redo_dma = 0;
> int ret = 0;
> - int err;
> + int sg_offset;
>
> /* wait for DMA complete status */
> then = jiffies;
> - if (1)
> while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x03)) {
> ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ * 1)) {
> - IVTV_DEBUG_WARN("ENC: REG_DMASTATUS 1 wait failed\n");
> + if ((jiffies - then) > (HZ * 3)) {
> + IVTV_DEBUG_WARN("ENC: REG_DMASTATUS wait failed\n");
> break;
> }
> }
> @@ -682,14 +653,14 @@
> then = jiffies;
> while ((readl(itv->reg_mem + IVTV_REG_DMAXFER) & 0x03)) {
> ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ * 1)) {
> - IVTV_DEBUG_WARN("ENC: REG_DMAXFER 1 wait failed\n");
> + if ((jiffies - then) > (HZ * 3)) {
> + IVTV_DEBUG_WARN("ENC: REG_DMAXFER wait failed\n");
> break;
> }
> }
>
> -redo_dma:
> - err = 0;
> + redo_dma:
> +
> spin_lock_irqsave(&itv->DMA_slock, flags);
> /* put SG Handle into register 0x0c */
> ivtv_write_reg(st->SG_handle, itv->reg_mem + IVTV_REG_ENCDMAADDR);
> @@ -703,36 +674,49 @@
> ivtv_write_reg(readl(itv->reg_mem + IVTV_REG_DMAXFER) |
> 0x02, itv->reg_mem + IVTV_REG_DMAXFER);
> }
> - else {
> - err = 1;
> - }
> spin_unlock_irqrestore(&itv->DMA_slock, flags);
>
> /* wait for DMA to start */
> then = jiffies;
> -
> - while (!err && (readl(itv->reg_mem + IVTV_REG_DMAXFER) & 0x02)) {
> - u32 stat = readl(itv->reg_mem + IVTV_REG_DMASTATUS);
> + while ((readl(itv->reg_mem + IVTV_REG_DMAXFER) & 0x02)) {
> /* DMA Error */
> - if (stat & 0x1a)
> + if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1A) {
> break;
> + }
>
> - //ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ / 5)) {
> + ivtv_sleep_timeout(HZ / 100, 1);
> + if ((jiffies - then) > (HZ * 3)) {
> IVTV_DEBUG_WARN("ENC: REG_DMAXFER 2 wait failed\n");
> - err = 1;
> + break;
> + }
> + }
> +
> + /* wait for DMA to be finished, check interrupt bit */
> + if (st->SG_length <= 8)
> + sg_offset = ((12 * st->SG_length) - 4);
> + else
> + sg_offset = ((12 * (st->SG_length % 8)) - 4);
> + then = jiffies;
> + while (!(readl(itv->reg_mem +
> + IVTV_REG_ENCSG1SRC + sg_offset) & 0x80000000)) {
> + /* DMA Error */
> + if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1A)
> + break;
> +
> + ivtv_sleep_timeout(HZ / 100, 1);
> + if ((jiffies - then) > (HZ * 3)) {
> + IVTV_DEBUG_WARN("DEC: REG_ENCSG1LEN wait failed\n");
> break;
> }
> }
>
> /* Wait for Write Interrupt */
> - while (!err && !(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1a) &&
> + while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1A) &&
> wait_event_interruptible(itv->w_intr_wq,
> atomic_read(&itv->w_intr))) {
> /* DMA Error */
> - if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1a) {
> + if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1A)
> break;
> - }
>
> if (atomic_read(&itv->w_intr))
> break;
> @@ -742,27 +726,24 @@
>
> /* wait for DMA complete status */
> then = jiffies;
> -
> - while (!err && !(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x02)) {
> + while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x02)) {
> /* DMA Error */
> - if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x18) {
> + if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x1A) {
> break;
> }
>
> ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ / 50)) {
> - err = 1;
> - IVTV_DEBUG_WARN("ENC: REG_DMASTATUS 2 wait failed\n");
> + if ((jiffies - then) > (HZ * 3)) {
> + IVTV_DEBUG_WARN("ENC: REG_DMASTATUS2 wait failed\n");
> break;
> }
> }
>
> /* DMA Error */
> - if (err || (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x18)) {
> - IVTV_DEBUG_WARN("ENC: (%d) DMA Error 0x%08x %08x\n",
> + if ((readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x18)) {
> + IVTV_DEBUG_WARN("ENC: (%d) DMA Error 0x%08x\n",
> redo_dma, readl(itv->reg_mem +
> - IVTV_REG_DMASTATUS),
> - readl(itv->reg_mem + IVTV_REG_IRQSTATUS));
> + IVTV_REG_DMASTATUS));
>
> /* Reset DMA Error, cancel last DMA? */
> spin_lock_irqsave(&itv->DMA_slock, flags);
> @@ -777,6 +758,7 @@
> IVTV_DEBUG_WARN("ENC: REDO DMA took too many tries.\n");
> ret = -ENOMEM;
> }
> +
> return ret;
> }
>
> @@ -786,7 +768,6 @@
> u64 pts_stamp;
> struct ivtv_stream *st;
> int x;
> - void *src;
> struct ivtv_buffer *buf = 0;
> LIST_HEAD(free_list);
> long sequence;
> @@ -818,7 +799,6 @@
> itv->vbi_frame += itv->vbi_fpi;
> size = itv->vbi_enc_size * itv->vbi_fpi;
> offset = bufptr;
> - src = (void *)(itv->enc_mem + offset);
>
> IVTV_DEBUG_DMA(
> "VBI(%d) BufPTR: 0x%08x offset 0x%08x size 0x%08x\n",
> @@ -840,7 +820,6 @@
> pio_mode = 1; /* Seems DMA mode has errors */
> offset = readl(itv->dec_mem + itv->vbi_dec_start);
> offset += itv->vbi_dec_start;
> - src = (void *)(itv->dec_mem + offset);
> size = readl(itv->dec_mem + itv->vbi_dec_start + 4);
> size += 8;
> pts_stamp = 0;
> @@ -938,8 +917,6 @@
> sequence = ++st->seq;
>
> st->ubytes = bytes_received;
> - st->buf_backup = readl(src);
> - writel(0x000001fe, src);
>
> for (x = 0; bytes_read < bytes_received; x++) {
> /* extract the buffers we procured earlier */
> @@ -992,11 +969,11 @@
> /* Sync SG buffers */
> pci_dma_sync_single_for_device((struct pci_dev *)itv->dev,
> buf->dma_handle,
> - buf->buffer.length + 256,
> st->dma);
> + buf->buffer.length, st->dma);
> #else
> /* Sync SG buffers */
> pci_dma_sync_single(itv->dev, buf->dma_handle,
> - buf->buffer.length + 256, st->dma);
> + buf->buffer.length, st->dma);
> #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 8) */
>
> ivtv_enq_buf_nolock(&st->dma_q, buf);
> @@ -1030,7 +1007,7 @@
>
> if (pio_mode) {
> /* Gather Buffers from DMA xfer to read */
> - ivtv_FROM_DMA_done(itv, st->type, src);
> + ivtv_FROM_DMA_done(itv, st->type);
> } else {
> //down(&itv->DMA_lock);
> if (dma_from_device(itv, st) != 0) {
> @@ -1038,7 +1015,7 @@
> }
> //up(&itv->DMA_lock);
>
> - ivtv_FROM_DMA_done(itv, st->type, src);
> + ivtv_FROM_DMA_done(itv, st->type);
> }
>
> clear_bit(IVTV_F_S_DMAP, &st->s_flags);
> diff -ur ivtv-0.8.1.orig/driver/ivtv-queue.c ivtv-0.8.1/driver/ivtv-queue.c
> --- ivtv-0.8.1.orig/driver/ivtv-queue.c 2006-11-19 13:07:58.000000000
> +0100
> +++ ivtv-0.8.1/driver/ivtv-queue.c 2006-12-01 16:48:38.000000000 +0100
> @@ -127,7 +127,7 @@
> /* UnMap Buffer */
> if (st->dma != PCI_DMA_NONE) {
> pci_unmap_single(itv->dev, item->dma_handle,
> - item->buffer.length + 256, st->dma);
> + item->buffer.length, st->dma);
> }
>
> kfree((void *)item->buffer.m.userptr);
> @@ -237,7 +237,7 @@
> IVTV_DEBUG_WARN("No memory on ivtv_buffer alloc!\n");
> return NULL;
> }
> - buf->buffer.m.userptr = (unsigned long)kmalloc(st->bufsize+256,
> GFP_KERNEL);
> + buf->buffer.m.userptr = (unsigned long)kmalloc(st->bufsize, GFP_KERNEL);
>
> if (buf->buffer.m.userptr == 0) {
> kfree(buf);
> @@ -288,7 +288,7 @@
> if (st->dma != PCI_DMA_NONE) {
> buf->dma_handle = pci_map_single(itv->dev,
> (void *)buf->buffer.m.userptr,
> - buf->buffer.length + 256,
> st->dma);
> + buf->buffer.length, st->dma);
> }
>
> return buf;
> @@ -839,7 +839,6 @@
> int ret = 0;
> /* wait for DMA complete status */
> then = jiffies;
> - if (1)
> while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x03)) {
> ivtv_sleep_timeout(HZ / 100, 1);
> if ((jiffies - then) > (HZ * 3)) {
> @@ -853,7 +852,7 @@
> then = jiffies;
> while ((readl(itv->reg_mem + IVTV_REG_DMAXFER) & 0x03)) {
> ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ / 5)) {
> + if ((jiffies - then) > (HZ * 3)) {
> IVTV_DEBUG_WARN(
> "DMA_TO: REG_DMAXFER wait failed\n");
> break;
> @@ -884,21 +883,33 @@
>
> /* wait for DMA to start */
> then = jiffies;
> -
> while ((readl(itv->reg_mem + IVTV_REG_DMAXFER) & 0x01)) {
> /* DMA Error */
> if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x15) {
> break;
> }
>
> - //ivtv_sleep_timeout(HZ / 100, 1);
> - if ((jiffies - then) > (HZ /5)) {
> + ivtv_sleep_timeout(HZ / 100, 1);
> + if ((jiffies - then) > (HZ * 3)) {
> IVTV_DEBUG_WARN(
> "DMA_TO: REG_DMAXFER 2 wait failed\n");
> break;
> }
> }
>
> + then = jiffies;
> + while (!(readl(itv->reg_mem + IVTV_REG_DECSG1LEN) & 0x80000000)) {
> + /* DMA Error */
> + if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x15)
> + break;
> +
> + ivtv_sleep_timeout(HZ / 100, 1);
> + if ((jiffies - then) > (HZ * 3)) {
> + IVTV_DEBUG_WARN(
> + "DEC: REG_DECSG1LEN wait failed\n");
> + break;
> + }
> + }
> /* Wait for Read Interrupt */
> while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x15) &&
> wait_event_interruptible(itv->r_intr_wq,
> @@ -913,7 +924,6 @@
> atomic_set(&itv->r_intr, 0);
> /* wait for DMA complete status */
> then = jiffies;
> -
> while (!(readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x01)) {
> /* DMA Error */
> if (readl(itv->reg_mem + IVTV_REG_DMASTATUS) & 0x15) {
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> ivtv-devel mailing list
> [email protected]
> http://ivtvdriver.org/mailman/listinfo/ivtv-devel
_______________________________________________
ivtv-devel mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-devel