modify performance of dwdam interrupt method
author倪振宇 <nzy@rock-chips.com>
Fri, 7 May 2010 11:56:48 +0000 (11:56 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:34:49 +0000 (13:34 +0800)
arch/arm/mach-rk2818/dma.c
arch/arm/mach-rk2818/include/mach/dma.h

index bcd2924e9b2bb0defcf8dff7f6f329bb4993e36f..8e171da27415f03f53f13608fb1e1db27f8752dc 100644 (file)
@@ -29,6 +29,8 @@
 
 static struct rk2818_dma rk2818_dma[MAX_DMA_CHANNELS];
 
+static struct tasklet_struct rk2818_dma_tasklet;
+
 const static char *rk28_dma_dev_id[] = {
     "sd_mmc",
     "uart_2",
@@ -427,7 +429,9 @@ static int rk28_dma_disable(unsigned int dma_ch, dma_t *dma_t)
        spin_lock(&rk28dma->lock);
        
        DISABLE_DWDMA(dma_ch);
-       
+       while (GET_DWDMA_STATUS(dma_ch))
+               cpu_relax();
+               
        spin_unlock(&rk28dma->lock);
        
     return 0;  
@@ -472,14 +476,11 @@ static int rk28_dma_request(unsigned int dma_ch, dma_t *dma_t)
         rk28dma->dma_llp_phy = NULL;
     }
     
-    rk2818_dma[dma_ch].dev_info = &rk28_dev_info[i];
+    rk28dma->dev_info = &rk28_dev_info[i];
        
        /* clear interrupt */
     CLR_DWDMA_INTR(dma_ch);
 
-       /* Unmask interrupt */
-    UN_MASK_DWDMA_INTR(dma_ch);
-
        spin_unlock(&rk28dma->lock);
 
     //printk(KERN_INFO "exit dwdma request device %d\n", i);
@@ -502,9 +503,6 @@ static int rk28_dma_free(unsigned int dma_ch, dma_t *dma_t)
        /* clear interrupt */
     CLR_DWDMA_INTR(dma_ch);
 
-       /* Mask interrupt */
-    MASK_DWDMA_INTR(dma_ch);
-
        if (dma_ch < RK28_DMA_CH2) {
         if (!rk28dma->dma_llp_vir) {
             printk(KERN_ERR "dma_free: no dma space can be free by virtual channel %d\n", dma_ch);  
@@ -580,14 +578,14 @@ static int rk28_dma_next(unsigned int dma_ch)
 }
 
 /**
- * rk28_dma_irq_handler - irq callback function   
+ * rk28_dma_tasklet - irq callback function   
  *
  */
-static irqreturn_t rk28_dma_irq_handler(int irq, void *dev_id)
+static void rk28_dma_tasklet(unsigned long data)
 {
        int i, raw_status;
     struct rk2818_dma *rk28dma;
-                    
+
     raw_status = read_dma_reg(DWDMA_RawTfr);
     
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -604,12 +602,33 @@ static irqreturn_t rk28_dma_irq_handler(int irq, void *dev_id)
             rk28dma->dma_t.active = 0;
             
             if (rk28dma->dma_t.irqHandle) {
-                rk28dma->dma_t.irqHandle(i, rk28dma->dma_t.data);
+                void *data = rk28dma->dma_t.data;
+                rk28dma->dma_t.irqHandle(i, data);
             } else {
-                //printk(KERN_WARNING "dma_irq: no IRQ handler for DMA channel %d\n", i);
+                printk(KERN_WARNING "dma_irq: no IRQ handler for DMA channel %d\n", i);
             }
         }
        }
+       /*
+        * Re-enable interrupts
+        */
+       UN_MASK_DWDMA_ALL_TRF_INTR;
+}
+
+/**
+ * rk28_dma_irq_handler - irq callback function   
+ *
+ */
+static irqreturn_t rk28_dma_irq_handler(int irq, void *dev_id)
+{
+       /*
+        * Just disable the interrupts. We'll turn them back on in the
+        * softirq handler.
+        */
+       MASK_DWDMA_ALL_TRF_INTR;
+       
+    tasklet_schedule(&rk2818_dma_tasklet);
+
        return IRQ_HANDLED;
 }
 
@@ -632,12 +651,6 @@ static int __init rk28_dma_init(void)
 
     printk(KERN_INFO "enter dwdma init\n");
 
-       ret = request_irq(RK28_DMA_IRQ_NUM, rk28_dma_irq_handler, 0, "DMA", NULL);
-       if (ret < 0) {
-               printk(KERN_CRIT "Can't register IRQ for DMA\n");
-               return ret;
-       }
-
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
                rk2818_dma[i].dma_t.irqHandle = NULL;
                rk2818_dma[i].dma_t.data = NULL;
@@ -653,9 +666,6 @@ static int __init rk28_dma_init(void)
         rk2818_dma[i].length = 0;
        }
        
-       /* enable DMA module */
-       write_dma_reg(DWDMA_DmaCfgReg, 0x01);
-
        /* clear all interrupts */
        write_dma_reg(DWDMA_ClearBlock, 0x3f3f);
        write_dma_reg(DWDMA_ClearTfr, 0x3f3f);
@@ -663,6 +673,26 @@ static int __init rk28_dma_init(void)
        write_dma_reg(DWDMA_ClearDstTran, 0x3f3f);
        write_dma_reg(DWDMA_ClearErr, 0x3f3f);
 
+    /*mask all interrupts*/
+       write_dma_reg(DWDMA_MaskBlock, 0x3f00);
+       write_dma_reg(DWDMA_MaskSrcTran, 0x3f00);
+       write_dma_reg(DWDMA_MaskDstTran, 0x3f00);
+       write_dma_reg(DWDMA_MaskErr, 0x3f00);
+
+    /*unmask transfer completion interrupt*/
+       UN_MASK_DWDMA_ALL_TRF_INTR;
+
+       ret = request_irq(RK28_DMA_IRQ_NUM, rk28_dma_irq_handler, 0, "DMA", NULL);
+       if (ret < 0) {
+               printk(KERN_CRIT "Can't register IRQ for DMA\n");
+               return ret;
+       }
+
+       tasklet_init(&rk2818_dma_tasklet, rk28_dma_tasklet, NULL);
+
+       /* enable DMA module */
+       write_dma_reg(DWDMA_DmaCfgReg, 0x01);
+
     printk(KERN_INFO "exit dwdma init\n");
     
        return 0;
index ee750adf5a81f63b8795756d4f217fbf248171d8..ace98858b1fc39f4bcd5ce85884ac9f354c5a1b4 100644 (file)
 #define CLR_DWDMA_INTR(dma_ch)            write_dma_reg(DWDMA_ClearTfr, 0x101<<dma_ch)
 
    /* Unmask interrupt */
-#define UN_MASK_DWDMA_INTR(dma_ch)        mask_dma_reg(DWDMA_MaskTfr, 0x101<<dma_ch, 0x101<<dma_ch)
+#define UN_MASK_DWDMA_ALL_TRF_INTR        write_dma_reg(DWDMA_MaskTfr, 0x3f3f)//mask_dma_reg(DWDMA_MaskTfr, 0x101<<dma_ch, 0x101<<dma_ch)
 
    /* Mask interrupt */
-#define MASK_DWDMA_INTR(dma_ch)           mask_dma_reg(DWDMA_MaskTfr, 0x101<<dma_ch, 0x100<<dma_ch)
+#define MASK_DWDMA_ALL_TRF_INTR           write_dma_reg(DWDMA_MaskTfr, 0x3f00)//mask_dma_reg(DWDMA_MaskTfr, 0x101<<dma_ch, 0x100<<dma_ch)
 
    /* Enable channel */
 #define ENABLE_DWDMA(dma_ch)              mask_dma_reg(DWDMA_ChEnReg, 0x101<<dma_ch, 0x101<<dma_ch)
    /* Disable channel */
 #define DISABLE_DWDMA(dma_ch)             mask_dma_reg(DWDMA_ChEnReg, 0x101<<dma_ch, 0x100<<dma_ch)
 
+   /* Disable channel */
+#define GET_DWDMA_STATUS(dma_ch)          read_dma_reg(DWDMA_ChEnReg) & (0x001<<dma_ch)
+
 /**************************/
 
 #define RK28_DMA_IRQ_NUM   0
-#define RK28_MAX_DMA_LLPS      100 /*max dma sg count*/
+#define RK28_MAX_DMA_LLPS      64 /*max dma sg count*/
 
 #define RK28_DMA_CH0A1_MAX_LEN      4095U
 #define RK28_DMA_CH2_MAX_LEN        2047U
@@ -179,6 +182,8 @@ struct rk28_dma_llp {
     llp_t   *llp;
     unsigned int      ctll;
     unsigned int      size; 
+       unsigned int      sstat;
+       unsigned int      dstat;
 };
 
 struct rk28_dma_dev {
@@ -199,7 +204,7 @@ struct rk2818_dma {
        spinlock_t              lock;
 };
 
-//#define test_dma
+#define test_dma
 
 /*devicd id list*/
 #define RK28_DMA_SD_MMC        0