Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / arm / mach-imx / dma.c
index 4ca51dc..3657887 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;
 }