]> err.no Git - linux-2.6/commitdiff
[ARM] 3601/1: i.MX/MX1 DMA error handling for signaled channels only
authorPavel Pisa <ppisa@pikron.com>
Thu, 22 Jun 2006 21:21:03 +0000 (22:21 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 22 Jun 2006 21:21:03 +0000 (22:21 +0100)
Patch from Pavel Pisa

There has been bug, that dma_err_handler() touches even
channels not signaling error condition.

Problem noticed by Andrea Paterniani.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-imx/dma.c
include/asm-arm/arch-imx/imx-dma.h

index 4ca51dcf13ac6966dbfc4357ad4dc10d1bfcf657..36578871ecc870de68eca19e96c4afce4bd21b99 100644 (file)
@@ -15,6 +15,9 @@
  *             Changed to support scatter gather DMA
  *             by taking Russell's code from RiscPC
  *
+ *  2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Corrected error handling code.
+ *
  */
 
 #undef DEBUG
@@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
 int
 imx_dma_setup_handlers(imx_dmach_t dma_ch,
                       void (*irq_handler) (int, void *, struct pt_regs *),
-                      void (*err_handler) (int, void *, struct pt_regs *),
+                      void (*err_handler) (int, void *, struct pt_regs *, int),
                       void *data)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
@@ -463,43 +466,53 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
        int i, disr = DISR;
        struct imx_dma_channel *channel;
        unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
+       int errcode;
 
-       DISR = disr;
+       DISR = disr & err_mask;
        for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-               channel = &imx_dma_channels[i];
-
-               if ((err_mask & 1 << i) && channel->name
-                   && channel->err_handler) {
-                       channel->err_handler(i, channel->data, regs);
+               if(!(err_mask & (1 << i)))
                        continue;
-               }
-
-               imx_dma_channels[i].sg = NULL;
+               channel = &imx_dma_channels[i];
+               errcode = 0;
 
                if (DBTOSR & (1 << i)) {
-                       printk(KERN_WARNING
-                              "Burst timeout on channel %d (%s)\n",
-                              i, channel->name);
-                       DBTOSR |= (1 << i);
+                       DBTOSR = (1 << i);
+                       errcode |= IMX_DMA_ERR_BURST;
                }
                if (DRTOSR & (1 << i)) {
-                       printk(KERN_WARNING
-                              "Request timeout on channel %d (%s)\n",
-                              i, channel->name);
-                       DRTOSR |= (1 << i);
+                       DRTOSR = (1 << i);
+                       errcode |= IMX_DMA_ERR_REQUEST;
                }
                if (DSESR & (1 << i)) {
-                       printk(KERN_WARNING
-                              "Transfer timeout on channel %d (%s)\n",
-                              i, channel->name);
-                       DSESR |= (1 << i);
+                       DSESR = (1 << i);
+                       errcode |= IMX_DMA_ERR_TRANSFER;
                }
                if (DBOSR & (1 << i)) {
-                       printk(KERN_WARNING
-                              "Buffer overflow timeout on channel %d (%s)\n",
-                              i, channel->name);
-                       DBOSR |= (1 << i);
+                       DBOSR = (1 << i);
+                       errcode |= IMX_DMA_ERR_BUFFER;
                }
+
+               /*
+                * The cleaning of @sg field would be questionable
+                * there, because its value can help to compute
+                * remaining/transfered bytes count in the handler
+                */
+               /*imx_dma_channels[i].sg = NULL;*/
+
+               if (channel->name && channel->err_handler) {
+                       channel->err_handler(i, channel->data, regs, errcode);
+                       continue;
+               }
+
+               imx_dma_channels[i].sg = NULL;
+
+               printk(KERN_WARNING
+                      "DMA timeout on channel %d (%s) -%s%s%s%s\n",
+                      i, channel->name,
+                      errcode&IMX_DMA_ERR_BURST?    " burst":"",
+                      errcode&IMX_DMA_ERR_REQUEST?  " request":"",
+                      errcode&IMX_DMA_ERR_TRANSFER? " transfer":"",
+                      errcode&IMX_DMA_ERR_BUFFER?   " buffer":"");
        }
        return IRQ_HANDLED;
 }
index f2063c1d610d72f8a68a5a31a59fb25b59648d78..599f03e5a9efa5782914126797a9714d16a92d56 100644 (file)
@@ -46,7 +46,7 @@
 struct imx_dma_channel {
        const char *name;
        void (*irq_handler) (int, void *, struct pt_regs *);
-       void (*err_handler) (int, void *, struct pt_regs *);
+       void (*err_handler) (int, void *, struct pt_regs *, int errcode);
        void *data;
        dmamode_t  dma_mode;
        struct scatterlist *sg;
@@ -58,6 +58,10 @@ struct imx_dma_channel {
 
 extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
 
+#define IMX_DMA_ERR_BURST     1
+#define IMX_DMA_ERR_REQUEST   2
+#define IMX_DMA_ERR_TRANSFER  4
+#define IMX_DMA_ERR_BUFFER    8
 
 /* The type to distinguish channel numbers parameter from ordinal int type */
 typedef int imx_dmach_t;
@@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
 int
 imx_dma_setup_handlers(imx_dmach_t dma_ch,
                void (*irq_handler) (int, void *, struct pt_regs *),
-               void (*err_handler) (int, void *, struct pt_regs *), void *data);
+               void (*err_handler) (int, void *, struct pt_regs *, int), void *data);
 
 void imx_dma_enable(imx_dmach_t dma_ch);