MA-13203-2 [#imx-1237] Fix kernel panic when do video plaback with dual display on...
authorIvan.liu <xiaowen.liu@nxp.com>
Tue, 13 Nov 2018 01:00:17 +0000 (09:00 +0800)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
BUG: scheduling while atomic: swapper/0/0/0x00010002
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.62 #1
Call trace:
[<ffff00000808b2e0>] dump_backtrace+0x0/0x414
[<ffff00000808b708>] show_stack+0x14/0x1c
[<ffff000008fbd00c>] dump_stack+0x90/0xb0
[<ffff00000810b8fc>] __schedule_bug+0x50/0x6c
[<ffff000008fd3b18>] __schedule+0x720/0x8a8
[<ffff000008fd3cd8>] schedule+0x38/0x9c
[<ffff000008fd40f0>] schedule_preempt_disabled+0x20/0x38
[<ffff000008fd51d8>] __mutex_lock.isra.9+0x4dc/0x4fc
[<ffff000008fd5208>] __mutex_lock_slowpath+0x10/0x18
[<ffff000008fd5240>] mutex_lock+0x30/0x38
[<ffff000008b79960>] gckOS_DestroySignal+0x30/0xcc
[<ffff000008baa3b8>] viv_fence_release+0x24/0x38
[<ffff0000087babcc>] dma_fence_release+0x38/0xf4
[<ffff0000087bb55c>] dma_fence_array_release+0x78/0xac
[<ffff0000087babcc>] dma_fence_release+0x38/0xf4
[<ffff0000087bb748>] irq_dma_fence_array_work+0x40/0x4c
[<ffff0000081d2878>] irq_work_run_list+0x68/0xa8
[<ffff0000081d28dc>] irq_work_run+0x24/0x40
[<ffff000008092440>] handle_IPI+0x300/0x330
[<ffff00000808197c>] gic_handle_irq+0x8c/0x184

Replace signal mutex lock with spin lock to handle signal in irq.

Change-Id: Id18e68f03bcb96c2aaf3ca8a0055fe6a64e8d10a
Signed-off-by: Ivan.liu <xiaowen.liu@nxp.com>
Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c

index f8f08d9..5d82642 100644 (file)
@@ -225,9 +225,6 @@ struct _gckOS
 
     /* Signal management. */
 
-    /* Lock. */
-    struct mutex                signalMutex;
-
     /* signal id database. */
     gcsINTEGER_DB               signalDB;
 
@@ -274,7 +271,7 @@ typedef struct _gcsSIGNAL
     gctBOOL manualReset;
 
     /* The reference counter. */
-    atomic_t ref;
+    volatile int ref;
 
     /* The owner of the signal. */
     gctHANDLE process;
index 7be6e79..7e8eb1d 100644 (file)
@@ -276,11 +276,12 @@ _AllocateIntegerId(
 {
     int result;
     gctINT next;
+    unsigned long flags;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
     idr_preload(GFP_KERNEL | gcdNOWARN);
 
-    spin_lock(&Database->lock);
+    spin_lock_irqsave(&Database->lock, flags);
 
     next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
 
@@ -294,7 +295,7 @@ _AllocateIntegerId(
         Database->curr = *Id = result;
     }
 
-    spin_unlock(&Database->lock);
+    spin_unlock_irqrestore(&Database->lock, flags);
 
     idr_preload_end();
 
@@ -309,7 +310,7 @@ again:
         return gcvSTATUS_OUT_OF_MEMORY;
     }
 
-    spin_lock(&Database->lock);
+    spin_lock_irqsave(&Database->lock, flags);
 
     next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
 
@@ -321,7 +322,7 @@ again:
         Database->curr = *Id;
     }
 
-    spin_unlock(&Database->lock);
+    spin_unlock_irqstore(&Database->lock, flags);
 
     if (result == -EAGAIN)
     {
@@ -345,12 +346,13 @@ _QueryIntegerId(
     )
 {
     gctPOINTER pointer;
+    unsigned long flags;
 
-    spin_lock(&Database->lock);
+    spin_lock_irqsave(&Database->lock, flags);
 
     pointer = idr_find(&Database->idr, Id);
 
-    spin_unlock(&Database->lock);
+    spin_unlock_irqrestore(&Database->lock, flags);
 
     if (pointer)
     {
@@ -374,12 +376,8 @@ _DestroyIntegerId(
     IN gctUINT32 Id
     )
 {
-    spin_lock(&Database->lock);
-
     idr_remove(&Database->idr, Id);
 
-    spin_unlock(&Database->lock);
-
     return gcvSTATUS_OK;
 }
 
@@ -549,9 +547,6 @@ gckOS_Construct(
      * Initialize the signal manager.
      */
 
-    /* Initialize mutex. */
-    mutex_init(&os->signalMutex);
-
     /* Initialize signal id database lock. */
     spin_lock_init(&os->signalDB.lock);
 
@@ -5535,8 +5530,7 @@ gckOS_CreateSignal(
     init_waitqueue_head(&signal->wait);
     spin_lock_init(&signal->lock);
     signal->manualReset = ManualReset;
-
-    atomic_set(&signal->ref, 1);
+    signal->ref = 1;
 
 #if gcdANDROID_NATIVE_FENCE_SYNC
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
@@ -5589,7 +5583,7 @@ gckOS_DestroySignal(
 {
     gceSTATUS status;
     gcsSIGNAL_PTR signal;
-    gctBOOL acquired = gcvFALSE;
+    unsigned long flags;
 
     gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
 
@@ -5597,35 +5591,26 @@ gckOS_DestroySignal(
     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
 
-    mutex_lock(&Os->signalMutex);
-    acquired = gcvTRUE;
-
     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
 
+    spin_lock_irqsave(&Os->signalDB.lock, flags);
     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+    signal->ref--;
 
-    if (atomic_dec_and_test(&signal->ref))
+    if (signal->ref == 0)
     {
         gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
 
         /* Free the sgianl. */
         kfree(signal);
     }
-
-    mutex_unlock(&Os->signalMutex);
-    acquired = gcvFALSE;
+    spin_unlock_irqrestore(&Os->signalDB.lock, flags);
 
     /* Success. */
     gcmkFOOTER_NO();
     return gcvSTATUS_OK;
 
 OnError:
-    if (acquired)
-    {
-        /* Release the mutex. */
-        mutex_unlock(&Os->signalMutex);
-    }
-
     gcmkFOOTER();
     return status;
 }
@@ -5668,6 +5653,7 @@ gckOS_Signal(
     struct dma_fence * fence = gcvNULL;
 #  endif
 #endif
+    unsigned long flags;
 
     gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
 
@@ -5675,30 +5661,25 @@ gckOS_Signal(
     gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
 
-    mutex_lock(&Os->signalMutex);
-
     status = _QueryIntegerId(&Os->signalDB,
                              (gctUINT32)(gctUINTPTR_T)Signal,
                              (gctPOINTER)&signal);
 
     if (gcmIS_ERROR(status))
     {
-        mutex_unlock(&Os->signalMutex);
         gcmkONERROR(status);
     }
 
+    spin_lock_irqsave(&Os->signalDB.lock, flags);
     /*
      * Signal saved in event is not referenced. Inc reference here to avoid
      * concurrent issue: signaling the signal while another thread is destroying
      * it.
      */
-    atomic_inc(&signal->ref);
-
-    mutex_unlock(&Os->signalMutex);
-
-    gcmkONERROR(status);
 
     gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+    signal->ref++;
+    spin_unlock_irqrestore(&Os->signalDB.lock, flags);
 
     spin_lock(&signal->lock);
 
@@ -5740,17 +5721,17 @@ gckOS_Signal(
 #  endif
 #endif
 
-    mutex_lock(&Os->signalMutex);
+    spin_lock_irqsave(&Os->signalDB.lock, flags);
+    signal->ref --;
 
-    if (atomic_dec_and_test(&signal->ref))
+    if (signal->ref == 0)
     {
         gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
 
         /* Free the sgianl. */
         kfree(signal);
     }
-
-    mutex_unlock(&Os->signalMutex);
+    spin_unlock_irqrestore(&Os->signalDB.lock, flags);
 
     /* Success. */
     gcmkFOOTER_NO();
@@ -5975,32 +5956,32 @@ gckOS_MapSignal(
 {
     gceSTATUS status;
     gcsSIGNAL_PTR signal = gcvNULL;
+    unsigned long flags;
     gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
 
     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
     gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
 
-    mutex_lock(&Os->signalMutex);
-
     gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
 
-    if (atomic_inc_return(&signal->ref) <= 1)
+    spin_lock_irqsave(&Os->signalDB.lock, flags);
+    signal->ref++;
+
+    if (signal->ref <= 1)
     {
+        spin_unlock_irqrestore(&Os->signalDB.lock, flags);
         /* The previous value is 0, it has been deleted. */
         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
     }
 
     *MappedSignal = (gctSIGNAL) Signal;
-
-    mutex_unlock(&Os->signalMutex);
+    spin_unlock_irqrestore(&Os->signalDB.lock, flags);
 
     /* Success. */
     gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
     return gcvSTATUS_OK;
 
 OnError:
-    mutex_unlock(&Os->signalMutex);
-
     gcmkFOOTER_NO();
     return status;
 }