OSDN Git Service

msm: kgsl: Clear the interrupt immediately
authorHarshdeep Dhatt <hdhatt@codeaurora.org>
Wed, 7 Oct 2015 22:10:36 +0000 (16:10 -0600)
committerHarshdeep Dhatt <hdhatt@codeaurora.org>
Fri, 14 Oct 2016 22:41:30 +0000 (16:41 -0600)
Sometimes an interrupt from GPU is ignored while we
are still executing the previous interrupt. In order
to service any interrupt that was fired while executing
the interrupt handler, clear the interrupt register
immediately.
Also, clear the ADRENO_INT_RBBM_AHB_ERROR bit not before
but after it's serviced in its respective handler. This
will avoid firing the main interrupt handler a second
time.

CRs-Fixed: 1072781
Change-Id: Ie6b5a511f5b3077adae7d464de437f2aa893b0c9
Signed-off-by: Harshdeep Dhatt <hdhatt@codeaurora.org>
drivers/gpu/msm/adreno.c
drivers/gpu/msm/adreno.h
drivers/gpu/msm/adreno_a3xx.c
drivers/gpu/msm/adreno_a4xx.c
drivers/gpu/msm/adreno_a5xx.c

index 94d8280..68f4a34 100644 (file)
@@ -589,11 +589,21 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
        struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
        struct adreno_irq *irq_params = gpudev->irq;
        irqreturn_t ret = IRQ_NONE;
-       unsigned int status = 0, tmp;
+       unsigned int status = 0, tmp, int_bit;
        int i;
 
        adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
 
+       /*
+        * Clear all the interrupt bits but ADRENO_INT_RBBM_AHB_ERROR. Because
+        * even if we clear it here, it will stay high until it is cleared
+        * in its respective handler. Otherwise, the interrupt handler will
+        * fire again.
+        */
+       int_bit = ADRENO_INT_BIT(adreno_dev, ADRENO_INT_RBBM_AHB_ERROR);
+       adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
+                               status & ~int_bit);
+
        /* Loop through all set interrupts and call respective handlers */
        for (tmp = status; tmp != 0;) {
                i = fls(tmp) - 1;
@@ -612,9 +622,14 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 
        gpudev->irq_trace(adreno_dev, status);
 
-       if (status)
+       /*
+        * Clear ADRENO_INT_RBBM_AHB_ERROR bit after this interrupt has been
+        * cleared in its respective handler
+        */
+       if (status & int_bit)
                adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
-                               status);
+                               int_bit);
+
        return ret;
 
 }
index 0f3403c..a2af26c 100644 (file)
@@ -198,6 +198,10 @@ struct adreno_gpudev;
 /* Time to allow preemption to complete (in ms) */
 #define ADRENO_PREEMPT_TIMEOUT 10000
 
+#define ADRENO_INT_BIT(a, _bit) (((a)->gpucore->gpudev->int_bits) ? \
+               (adreno_get_int(a, _bit) < 0 ? 0 : \
+               BIT(adreno_get_int(a, _bit))) : 0)
+
 /**
  * enum adreno_preempt_states
  * ADRENO_PREEMPT_NONE: No preemption is scheduled
@@ -574,6 +578,11 @@ enum adreno_regs {
        ADRENO_REG_REGISTER_MAX,
 };
 
+enum adreno_int_bits {
+       ADRENO_INT_RBBM_AHB_ERROR,
+       ADRENO_INT_BITS_MAX,
+};
+
 /**
  * adreno_reg_offsets: Holds array of register offsets
  * @offsets: Offset array of size defined by enum adreno_regs
@@ -589,6 +598,7 @@ struct adreno_reg_offsets {
 #define ADRENO_REG_UNUSED      0xFFFFFFFF
 #define ADRENO_REG_SKIP        0xFFFFFFFE
 #define ADRENO_REG_DEFINE(_offset, _reg) [_offset] = _reg
+#define ADRENO_INT_DEFINE(_offset, _val) ADRENO_REG_DEFINE(_offset, _val)
 
 /*
  * struct adreno_vbif_data - Describes vbif register value pair
@@ -726,6 +736,7 @@ struct adreno_gpudev {
         * so define them in the structure and use them as variables.
         */
        const struct adreno_reg_offsets *reg_offsets;
+       unsigned int *const int_bits;
        const struct adreno_ft_perf_counters *ft_perf_counters;
        unsigned int ft_perf_counters_count;
 
@@ -1101,6 +1112,23 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev,
        return gpudev->reg_offsets->offsets[offset_name];
 }
 
+/*
+ * adreno_get_int() - Returns the offset value of an interrupt bit from
+ * the interrupt bit array in the gpudev node
+ * @adreno_dev:                Pointer to the the adreno device
+ * @bit_name:          The interrupt bit enum whose bit is returned
+ */
+static inline unsigned int adreno_get_int(struct adreno_device *adreno_dev,
+                               enum adreno_int_bits bit_name)
+{
+       struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+       if (bit_name >= ADRENO_INT_BITS_MAX)
+               return -ERANGE;
+
+       return gpudev->int_bits[bit_name];
+}
+
 /**
  * adreno_gpu_fault() - Return the current state of the GPU
  * @adreno_dev: A pointer to the adreno_device to query
index 97e7146..3f5a9c6 100644 (file)
@@ -1425,6 +1425,10 @@ static struct adreno_coresight a3xx_coresight = {
        .groups = a3xx_coresight_groups,
 };
 
+static unsigned int a3xx_int_bits[ADRENO_INT_BITS_MAX] = {
+       ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A3XX_INT_RBBM_AHB_ERROR),
+};
+
 /* Register offset defines for A3XX */
 static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
        ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A3XX_CP_ME_RAM_WADDR),
@@ -1853,6 +1857,7 @@ int a3xx_microcode_load(struct adreno_device *adreno_dev,
 
 struct adreno_gpudev adreno_a3xx_gpudev = {
        .reg_offsets = &a3xx_reg_offsets,
+       .int_bits = a3xx_int_bits,
        .ft_perf_counters = a3xx_ft_perf_counters,
        .ft_perf_counters_count = ARRAY_SIZE(a3xx_ft_perf_counters),
        .perfcounters = &a3xx_perfcounters,
index bfbdb0e..5ca04e5 100644 (file)
@@ -739,6 +739,10 @@ static void a4xx_err_callback(struct adreno_device *adreno_dev, int bit)
        }
 }
 
+static unsigned int a4xx_int_bits[ADRENO_INT_BITS_MAX] = {
+       ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A4XX_INT_RBBM_AHB_ERROR),
+};
+
 /* Register offset defines for A4XX, in order of enum adreno_regs */
 static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
        ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A4XX_CP_ME_RAM_WADDR),
@@ -1765,6 +1769,7 @@ static struct adreno_snapshot_data a4xx_snapshot_data = {
 
 struct adreno_gpudev adreno_a4xx_gpudev = {
        .reg_offsets = &a4xx_reg_offsets,
+       .int_bits = a4xx_int_bits,
        .ft_perf_counters = a4xx_ft_perf_counters,
        .ft_perf_counters_count = ARRAY_SIZE(a4xx_ft_perf_counters),
        .perfcounters = &a4xx_perfcounters,
index 2891940..860f6d2 100644 (file)
@@ -2872,6 +2872,10 @@ static struct adreno_ft_perf_counters a5xx_ft_perf_counters[] = {
        {KGSL_PERFCOUNTER_GROUP_TSE, A5XX_TSE_INPUT_PRIM_NUM},
 };
 
+static unsigned int a5xx_int_bits[ADRENO_INT_BITS_MAX] = {
+       ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A5XX_INT_RBBM_AHB_ERROR),
+};
+
 /* Register offset defines for A5XX, in order of enum adreno_regs */
 static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
        ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A5XX_CP_WFI_PEND_CTR),
@@ -3504,6 +3508,7 @@ static struct adreno_coresight a5xx_coresight = {
 
 struct adreno_gpudev adreno_a5xx_gpudev = {
        .reg_offsets = &a5xx_reg_offsets,
+       .int_bits = a5xx_int_bits,
        .ft_perf_counters = a5xx_ft_perf_counters,
        .ft_perf_counters_count = ARRAY_SIZE(a5xx_ft_perf_counters),
        .coresight = &a5xx_coresight,