From: Mike Rapoport <mike@compulab.co.il>
To: Robert Jarzmik <robert.jarzmik@free.fr>
Cc: video4linux-list@redhat.com, g.liakhovetski@gmx.de
Subject: Re: [PATCH] pxa_camera: Redesign DMA handling
Date: Tue, 03 Mar 2009 09:26:12 +0200 [thread overview]
Message-ID: <49ACDB94.2050001@compulab.co.il> (raw)
In-Reply-To: <1236021422-8074-1-git-send-email-robert.jarzmik@free.fr>
Robert,
Robert Jarzmik wrote:
> The DMA transfers in pxa_camera showed some weaknesses in
> multiple queued buffers context :
> - poll/select problem
> The order between list pcdev->capture and DMA chain was
> not the same. This creates a discrepancy between video
> buffers marked as "done" by the IRQ handler, and the
> really finished video buffer.
>
> - multiple buffers DMA starting
> When multiple buffers were queued, the DMA channels were
> always started right away. This is not optimal, as a
> special case appears when the first EOM was not yet
> reached, and the DMA channels were prematurely started.
>
> - YUV planar formats hole
> All planes were PAGE aligned (ie. 4096 bytes
> aligned). This is not consistent with YUV422 format,
> which requires Y, U and V planes glued together.
> The new implementation forces the alignement on 8 bytes
> (DMA requirement), which is almost always the case
> (granted by width x height being a multiple of 8).
>
> - Maintainability
> DMA code was a bit ofsuscated. Rationalize the code to be
> easily maintainable by anyone.
>
> This patch attemps to address these issues.
I think you did a great work.
Can you please split the patch into several pieces? Say, videobuf_prepare
related changes in one patch and videobuf_queue related changes in another?
> The test cases include tests in both YUV422 and RGB565 :
> - a picture of size 111 x 111 (cross RAM pages example)
> - a picture of size 1023 x 4 in (under 1 RAM page)
> - a picture of size 1024 x 4 in (exactly 1 RAM page)
> - a picture of size 1025 x 4 in (over 1 RAM page)
> - a picture of size 1280 x 1024 (many RAM pages)
Did you have a chance to test planar YUV422 with overlays?
> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
> ---
> drivers/media/video/pxa_camera.c | 400 +++++++++++++++++++++++---------------
> 1 files changed, 243 insertions(+), 157 deletions(-)
>
> diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
> index e3e6b29..ccedfaf 100644
> --- a/drivers/media/video/pxa_camera.c
> +++ b/drivers/media/video/pxa_camera.c
> @@ -243,12 +243,12 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
>
> /* planar capture requires Y, U and V buffers to be page aligned */
> if (pcdev->channels == 3) {
> - *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
> - *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
> - *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
> + *size = roundup(icd->width * icd->height, 8); /* Y pages */
> + *size += roundup(icd->width * icd->height / 2, 8); /* U pages */
> + *size += roundup(icd->width * icd->height / 2, 8); /* V pages */
> } else {
> - *size = icd->width * icd->height *
> - ((icd->current_fmt->depth + 7) >> 3);
> + *size = roundup(icd->width * icd->height *
> + ((icd->current_fmt->depth + 7) >> 3), 8);
> }
>
> if (0 == *count)
> @@ -289,19 +289,58 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
> buf->vb.state = VIDEOBUF_NEEDS_INIT;
> }
>
> +static int calculate_dma_sglen(struct scatterlist *sg, int sg_first,
> + int sg_first_ofs, int size)
> +{
> + int sg_i, offset;
> + int dma_len, xfer_len;
> +
> + offset = sg_first_ofs;
> + for (sg_i = sg_first; size > 0; sg_i++) {
> + dma_len = sg_dma_len(&sg[sg_i]);
> +
> + /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
> + xfer_len = roundup(min(dma_len - offset, size), 8);
> + size -= xfer_len;
> + offset = 0;
> + }
> +
> + return sg_i - sg_first;
> +}
> +
> +/**
> + * pxa_init_dma_channel - init dma descriptors
> + * @pcdev: pxa camera device
> + * @buf: pxa buffer to find pxa dma channel
> + * @dma: dma video buffer
> + * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V')
> + * @cibr: camera read fifo
> + * @size: bytes to transfer
> + * @sg_first: index of first element of sg_list
> + * @sg_first_ofs: offset in first element of sg_list
> + *
> + * Prepares the pxa dma descriptors to transfer one camera channel.
> + * Beware sg_first and sg_first_ofs are both input and output parameters.
> + *
> + * Returns 0
> + */
> static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
> struct pxa_buffer *buf,
> struct videobuf_dmabuf *dma, int channel,
> - int sglen, int sg_start, int cibr,
> - unsigned int size)
> + int cibr, int size,
> + int *sg_first, int *sg_first_ofs)
> {
> struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
> - int i;
> + struct scatterlist *sg = dma->sglist;
> + int i, offset, sg_i, sglen;
> + int dma_len = 0, xfer_len = 0;
>
> if (pxa_dma->sg_cpu)
> dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
> pxa_dma->sg_cpu, pxa_dma->sg_dma);
>
> + sglen = calculate_dma_sglen(sg, *sg_first, *sg_first_ofs, size);
> +
> pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
> pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
> &pxa_dma->sg_dma, GFP_KERNEL);
> @@ -309,27 +348,51 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
> return -ENOMEM;
>
> pxa_dma->sglen = sglen;
> + offset = *sg_first_ofs;
> +
> + dev_dbg(pcdev->dev, "DMA: sg_first=%d, sglen=%d, ofs=%d, dma.desc=%x\n",
> + *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
>
> - for (i = 0; i < sglen; i++) {
> - int sg_i = sg_start + i;
> - struct scatterlist *sg = dma->sglist;
> - unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len;
> + for (i = 0; size > 0; i++) {
> + sg_i = *sg_first + i;
> + dma_len = sg_dma_len(&sg[sg_i]);
>
> pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
> - pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]);
> + pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]) + offset;
>
> /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
> - xfer_len = (min(dma_len, size) + 7) & ~7;
> + xfer_len = roundup(min(dma_len - offset, size), 8);
>
> pxa_dma->sg_cpu[i].dcmd =
> - DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
> - size -= dma_len;
> + DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len
> + | ((i == 0) ? DCMD_STARTIRQEN : 0);
> + size -= xfer_len;
> pxa_dma->sg_cpu[i].ddadr =
> pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
> +
> + dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
> + pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
> + sg_dma_address(&sg[sg_i]) + offset, xfer_len);
> + offset = 0;
> }
>
> - pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP;
> - pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN;
> + pxa_dma->sg_cpu[i].ddadr = DDADR_STOP;
> + pxa_dma->sg_cpu[i].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN;
> +
> + *sg_first_ofs = xfer_len;
> + *sg_first = *sg_first + i;
> +
> + /*
> + * Handle 2 special cases :
> + * - if we finish the DMA transfer in the middle of a RAM page
> + * - if we finish the DMA transfer in the last 7 bytes of a RAM page
> + */
> + if (*sg_first_ofs != 0)
> + *sg_first -= 1;
> + if (*sg_first_ofs >= dma_len) {
> + *sg_first_ofs -= dma_len;
> + *sg_first += 1;
> + }
>
> return 0;
> }
> @@ -342,8 +405,8 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
> struct pxa_camera_dev *pcdev = ici->priv;
> struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
> int ret;
> - int sglen_y, sglen_yu = 0, sglen_u = 0, sglen_v = 0;
> - int size_y, size_u = 0, size_v = 0;
> + int sg_next = 0, next_ofs = 0;
> + int size_y = 0, size_u = 0, size_v = 0;
>
> dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
> vb, vb->baddr, vb->bsize);
> @@ -381,53 +444,50 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
> }
>
> if (vb->state == VIDEOBUF_NEEDS_INIT) {
> - unsigned int size = vb->size;
> + int size = vb->size;
> struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
>
> ret = videobuf_iolock(vq, vb, NULL);
> if (ret)
> goto fail;
>
> - if (pcdev->channels == 3) {
> - /* FIXME the calculations should be more precise */
> - sglen_y = dma->sglen / 2;
> - sglen_u = sglen_v = dma->sglen / 4 + 1;
> - sglen_yu = sglen_y + sglen_u;
> + switch (pcdev->channels) {
> + case 1:
> + size_y = size;
> + break;
> + case 3:
> size_y = size / 2;
> size_u = size_v = size / 4;
> - } else {
> - sglen_y = dma->sglen;
> - size_y = size;
> + break;
> }
>
> /* init DMA for Y channel */
> - ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y,
> - 0, 0x28, size_y);
> -
> + ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
> + &sg_next, &next_ofs);
> if (ret) {
> dev_err(pcdev->dev,
> "DMA initialization for Y/RGB failed\n");
> goto fail;
> }
>
> - if (pcdev->channels == 3) {
> - /* init DMA for U channel */
> - ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u,
> - sglen_y, 0x30, size_u);
> - if (ret) {
> - dev_err(pcdev->dev,
> - "DMA initialization for U failed\n");
> - goto fail_u;
> - }
> -
> - /* init DMA for V channel */
> - ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v,
> - sglen_yu, 0x38, size_v);
> - if (ret) {
> - dev_err(pcdev->dev,
> - "DMA initialization for V failed\n");
> - goto fail_v;
> - }
> + /* init DMA for U channel */
> + if (size_u)
> + ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
> + size_u, &sg_next, &next_ofs);
> + if (ret) {
> + dev_err(pcdev->dev,
> + "DMA initialization for U failed\n");
> + goto fail_u;
> + }
> +
> + /* init DMA for V channel */
> + if (size_v)
> + ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
> + size_u, &sg_next, &next_ofs);
> + if (ret) {
> + dev_err(pcdev->dev,
> + "DMA initialization for V failed\n");
> + goto fail_v;
> }
>
> vb->state = VIDEOBUF_PREPARED;
> @@ -453,6 +513,97 @@ out:
> return ret;
> }
>
> +/**
> + * pxa_dma_start_channels - start DMA channel for active buffer
> + * @pcdev: pxa camera device
> + *
> + * Initialize DMA channels to the beginning of the active video buffer, and
> + * start these channels.
> + */
> +static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
> +{
> + int i;
> + struct pxa_buffer *active;
> +
> + active = pcdev->active;
> +
> + for (i = 0; i < pcdev->channels; i++) {
> + dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__,
> + i, active->dmas[i].sg_dma);
> + DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
> + DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
> + }
> +}
> +
> +static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
> +{
> + int i;
> +
> + for (i = 0; i < pcdev->channels; i++) {
> + dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i);
> + DCSR(pcdev->dma_chans[i]) = 0;
> + }
> +}
> +
> +static void pxa_dma_update_sg_tail(struct pxa_camera_dev *pcdev,
> + struct pxa_buffer *buf)
> +{
> + int i;
> +
> + for (i = 0; i < pcdev->channels; i++) {
> + pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
> + pcdev->sg_tail[i]->ddadr = DDADR_STOP;
> + }
> +}
> +
> +static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
> + struct pxa_buffer *buf)
> +{
> + int i;
> +
> + for (i = 0; i < pcdev->channels; i++) {
> + if (!pcdev->sg_tail[i])
> + continue;
> + pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
> + }
> +
> + pxa_dma_update_sg_tail(pcdev, buf);
> +}
> +
> +/**
> + * pxa_camera_start_capture - start video capturing
> + * @pcdev: camera device
> + *
> + * Launch capturing. DMA channels should not be active yet. They should get
> + * activated at the end of frame interrupt, to capture only whole frames, and
> + * never begin the capture of a partial frame.
> + */
> +static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
> +{
> + unsigned long cicr0, cifr;
> +
> + dev_dbg(pcdev->dev, "%s\n", __func__);
> + cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
> + __raw_writel(cifr, pcdev->base + CIFR);
> +
> + cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB | CISR_IFO_0
> + | CISR_IFO_1 | CISR_IFO_2;
> + cicr0 &= ~CICR0_EOFM;
> + __raw_writel(cicr0, pcdev->base + CICR0);
> +}
> +
> +static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
> +{
> + unsigned long cicr0;
> +
> + pxa_dma_stop_channels(pcdev);
> +
> + cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
> + __raw_writel(cicr0, pcdev->base + CICR0);
> +
> + dev_dbg(pcdev->dev, "%s\n", __func__);
> +}
> +
> static void pxa_videobuf_queue(struct videobuf_queue *vq,
> struct videobuf_buffer *vb)
> {
> @@ -462,10 +613,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
> struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
> struct pxa_buffer *active;
> unsigned long flags;
> - int i;
>
> - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
> - vb, vb->baddr, vb->bsize);
> + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__,
> + vb, vb->baddr, vb->bsize, pcdev->active);
> spin_lock_irqsave(&pcdev->lock, flags);
>
> list_add_tail(&vb->queue, &pcdev->capture);
> @@ -473,68 +623,14 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
> vb->state = VIDEOBUF_ACTIVE;
> active = pcdev->active;
>
> - if (!active) {
> - unsigned long cifr, cicr0;
> + pxa_dma_stop_channels(pcdev);
>
> - cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
> - __raw_writel(cifr, pcdev->base + CIFR);
> + pxa_dma_add_tail_buf(pcdev, buf);
>
> - for (i = 0; i < pcdev->channels; i++) {
> - DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
> - DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
> - pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1;
> - }
> -
> - pcdev->active = buf;
> -
> - cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
> - __raw_writel(cicr0, pcdev->base + CICR0);
> - } else {
> - struct pxa_cam_dma *buf_dma;
> - struct pxa_cam_dma *act_dma;
> - int nents;
> -
> - for (i = 0; i < pcdev->channels; i++) {
> - buf_dma = &buf->dmas[i];
> - act_dma = &active->dmas[i];
> - nents = buf_dma->sglen;
> -
> - /* Stop DMA engine */
> - DCSR(pcdev->dma_chans[i]) = 0;
> -
> - /* Add the descriptors we just initialized to
> - the currently running chain */
> - pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;
> - pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;
> -
> - /* Setup a dummy descriptor with the DMA engines current
> - * state
> - */
> - buf_dma->sg_cpu[nents].dsadr =
> - pcdev->res->start + 0x28 + i*8; /* CIBRx */
> - buf_dma->sg_cpu[nents].dtadr =
> - DTADR(pcdev->dma_chans[i]);
> - buf_dma->sg_cpu[nents].dcmd =
> - DCMD(pcdev->dma_chans[i]);
> -
> - if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) {
> - /* The DMA engine is on the last
> - descriptor, set the next descriptors
> - address to the descriptors we just
> - initialized */
> - buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma;
> - } else {
> - buf_dma->sg_cpu[nents].ddadr =
> - DDADR(pcdev->dma_chans[i]);
> - }
> -
> - /* The next descriptor is the dummy descriptor */
> - DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents *
> - sizeof(struct pxa_dma_desc);
> -
> - DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
> - }
> - }
> + if (!active)
> + pxa_camera_start_capture(pcdev);
> + else
> + pxa_dma_start_channels(pcdev);
>
> spin_unlock_irqrestore(&pcdev->lock, flags);
> }
> @@ -572,7 +668,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
> struct videobuf_buffer *vb,
> struct pxa_buffer *buf)
> {
> - unsigned long cicr0;
> + int i;
>
> /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
> list_del_init(&vb->queue);
> @@ -580,15 +676,13 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
> do_gettimeofday(&vb->ts);
> vb->field_count++;
> wake_up(&vb->done);
> + dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
>
> if (list_empty(&pcdev->capture)) {
> + pxa_camera_stop_capture(pcdev);
> pcdev->active = NULL;
> - DCSR(pcdev->dma_chans[0]) = 0;
> - DCSR(pcdev->dma_chans[1]) = 0;
> - DCSR(pcdev->dma_chans[2]) = 0;
> -
> - cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
> - __raw_writel(cicr0, pcdev->base + CICR0);
> + for (i = 0; i < pcdev->channels; i++)
> + pcdev->sg_tail[i] = NULL;
> return;
> }
>
> @@ -603,19 +697,23 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
> unsigned long flags;
> u32 status, camera_status, overrun;
> struct videobuf_buffer *vb;
> - unsigned long cifr, cicr0;
>
> spin_lock_irqsave(&pcdev->lock, flags);
>
> status = DCSR(channel);
> - DCSR(channel) = status | DCSR_ENDINTR;
> + DCSR(channel) = status | DCSR_STARTINTR | DCSR_ENDINTR;
> +
> + camera_status = __raw_readl(pcdev->base + CISR);
> + overrun = CISR_IFO_0;
> + if (pcdev->channels == 3)
> + overrun |= CISR_IFO_1 | CISR_IFO_2;
>
> if (status & DCSR_BUSERR) {
> dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
> goto out;
> }
>
> - if (!(status & DCSR_ENDINTR)) {
> + if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
> dev_err(pcdev->dev, "Unknown DMA IRQ source, "
> "status: 0x%08x\n", status);
> goto out;
> @@ -626,38 +724,27 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
> goto out;
> }
>
> - camera_status = __raw_readl(pcdev->base + CISR);
> - overrun = CISR_IFO_0;
> - if (pcdev->channels == 3)
> - overrun |= CISR_IFO_1 | CISR_IFO_2;
> - if (camera_status & overrun) {
> - dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
> - /* Stop the Capture Interface */
> - cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
> - __raw_writel(cicr0, pcdev->base + CICR0);
> -
> - /* Stop DMA */
> - DCSR(channel) = 0;
> - /* Reset the FIFOs */
> - cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
> - __raw_writel(cifr, pcdev->base + CIFR);
> - /* Enable End-Of-Frame Interrupt */
> - cicr0 &= ~CICR0_EOFM;
> - __raw_writel(cicr0, pcdev->base + CICR0);
> - /* Restart the Capture Interface */
> - __raw_writel(cicr0 | CICR0_ENB, pcdev->base + CICR0);
> - goto out;
> - }
> -
> vb = &pcdev->active->vb;
> buf = container_of(vb, struct pxa_buffer, vb);
> WARN_ON(buf->inwork || list_empty(&vb->queue));
> - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
> - vb, vb->baddr, vb->bsize);
>
> - buf->active_dma &= ~act_dma;
> - if (!buf->active_dma)
> - pxa_camera_wakeup(pcdev, vb, buf);
> + dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
> + __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
> + status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
> +
> + if (status & DCSR_ENDINTR) {
> + if (camera_status & overrun) {
> + dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n",
> + camera_status);
> + pxa_camera_stop_capture(pcdev);
> + pxa_camera_start_capture(pcdev);
> + goto out;
> + }
> +
> + buf->active_dma &= ~act_dma;
> + if (!buf->active_dma)
> + pxa_camera_wakeup(pcdev, vb, buf);
> + }
>
> out:
> spin_unlock_irqrestore(&pcdev->lock, flags);
> @@ -796,12 +883,11 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
> __raw_writel(status, pcdev->base + CISR);
>
> if (status & CISR_EOF) {
> - int i;
> - for (i = 0; i < pcdev->channels; i++) {
> - DDADR(pcdev->dma_chans[i]) =
> - pcdev->active->dmas[i].sg_dma;
> - DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
> - }
> + pcdev->active = list_first_entry(&pcdev->capture,
> + struct pxa_buffer, vb.queue);
> +
> + pxa_dma_start_channels(pcdev);
> +
> cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
> __raw_writel(cicr0, pcdev->base + CICR0);
> }
--
Sincerely yours,
Mike.
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
next prev parent reply other threads:[~2009-03-03 7:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-02 19:17 [PATCH] pxa_camera: Redesign DMA handling Robert Jarzmik
2009-03-03 7:26 ` Mike Rapoport [this message]
2009-03-03 15:49 ` Guennadi Liakhovetski
2009-03-03 18:47 ` Robert Jarzmik
2009-03-07 23:11 ` Guennadi Liakhovetski
2009-03-08 0:39 ` Robert Jarzmik
2009-03-04 18:11 ` Robert Jarzmik
2009-03-11 12:22 ` Guennadi Liakhovetski
[not found] <722242271.3317321236779109198.JavaMail.root@zimbra20-e3.priv.proxad.net>
2009-03-11 13:48 ` robert.jarzmik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49ACDB94.2050001@compulab.co.il \
--to=mike@compulab.co.il \
--cc=g.liakhovetski@gmx.de \
--cc=robert.jarzmik@free.fr \
--cc=video4linux-list@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.