summaryrefslogtreecommitdiff
path: root/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
diff options
context:
space:
mode:
authorShawn Xiao <b49994@freescale.com>2015-06-12 13:08:42 +0800
committerShawn Xiao <b49994@freescale.com>2015-06-12 13:14:49 +0800
commit6eefa0c21fd6b2ce9058ab53d375430ba13673d7 (patch)
tree7b4684dc2ffabb6030b0a440d45e39de03463e6e /drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
parent6d5f951e94237c818576f4bcc6577d833f151804 (diff)
MGS-532 [#1630] P13 driver meet "AXI BUS ERROR" on GC2000rel_imx_3.10.17_1.0.3_patch
When run Antutu benchmark several times continuously, it will show "AXI BUS ERROR". The root cause is When unlock a surface, driver must flush its GPU cache. Otherwise, GPU may write out the cache after GPU address is freed, which will cause MMU Exception or AXI bus error. Even if GPU address isn't freed, data in cache may pollute memory after memory is used by another surface. The solution is Before an event is written to command buffer, driver checks the group of records linked to this event to find out which kinds of cache need to flush. This method doesn't care whether the record is from user side or kernel. And driver generates only one flush for a group of records. Date: Jun 11, 2015 Signed-off-by: Meng Mingming <b51843@freescale.com>
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c')
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c133
1 files changed, 118 insertions, 15 deletions
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
index 7b84245badc6..8d863d7a250c 100644
--- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
@@ -378,6 +378,69 @@ _SubmitTimerFunction(
gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
}
+/*******************************************************************************
+**
+** _QueryFlush
+**
+** Check the type of surfaces which will be released by current event and
+** determine the cache needed to flush.
+**
+*/
+static gceSTATUS
+_QueryFlush(
+ IN gckEVENT Event,
+ IN gcsEVENT_PTR Record,
+ OUT gceKERNEL_FLUSH *Flush
+ )
+{
+ gceKERNEL_FLUSH flush = 0;
+ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+ gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+ while (Record != gcvNULL)
+ {
+ switch (Record->info.command)
+ {
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ switch(Record->info.u.UnlockVideoMemory.type)
+ {
+ case gcvSURF_TILE_STATUS:
+ flush |= gcvFLUSH_TILE_STATUS;
+ break;
+ case gcvSURF_RENDER_TARGET:
+ flush |= gcvFLUSH_COLOR;
+ break;
+ case gcvSURF_DEPTH:
+ flush |= gcvFLUSH_DEPTH;
+ break;
+ case gcvSURF_TEXTURE:
+ flush |= gcvFLUSH_TEXTURE;
+ break;
+ case gcvSURF_TYPE_UNKNOWN:
+ gcmkASSERT(0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case gcvHAL_UNMAP_USER_MEMORY:
+ *Flush = gcvFLUSH_ALL;
+ return gcvSTATUS_OK;
+ break;
+
+ default:
+ break;
+ }
+
+ Record = Record->next;
+ }
+
+ *Flush = flush;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
/******************************************************************************\
******************************* gckEVENT API Code *******************************
\******************************************************************************/
@@ -1504,10 +1567,19 @@ gckEVENT_Submit(
gctPOINTER buffer;
#endif
+ gctSIZE_T flushBytes;
+ gctUINT32 executeBytes;
+ gckHARDWARE hardware;
+
+ gceKERNEL_FLUSH flush = gcvFALSE;
+
gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
/* Get gckCOMMAND object. */
command = Event->kernel->command;
+ hardware = Event->kernel->hardware;
+
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
/* Are there event queues? */
if (Event->queueHead != gcvNULL)
@@ -1552,6 +1624,9 @@ gckEVENT_Submit(
gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
acquired = gcvFALSE;
+ /* Determine cache needed to flush. */
+ gcmkVERIFY_OK(_QueryFlush(Event, Event->queues[id].head, &flush));
+
#if gcdNULL_DRIVER
/* Notify immediately on infinite hardware. */
gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
@@ -1559,27 +1634,55 @@ gckEVENT_Submit(
gcmkONERROR(gckEVENT_Notify(Event, 0));
#else
/* Get the size of the hardware event. */
- gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
- gcvNULL,
- id,
- Event->queues[id].source,
- &bytes));
+ gcmkONERROR(gckHARDWARE_Event(
+ hardware,
+ gcvNULL,
+ id,
+ Event->queues[id].source,
+ &bytes
+ ));
+
+ /* Get the size of flush command. */
+ gcmkONERROR(gckHARDWARE_Flush(
+ hardware,
+ flush,
+ gcvNULL,
+ &flushBytes
+ ));
+
+ bytes += flushBytes;
+
+ /* Total bytes need to execute. */
+ executeBytes = bytes;
/* Reserve space in the command queue. */
- gcmkONERROR(gckCOMMAND_Reserve(command,
- bytes,
- &buffer,
- &bytes));
+ gcmkONERROR(gckCOMMAND_Reserve(command, bytes, &buffer, &bytes));
+
+ /* Set the flush in the command queue. */
+ gcmkONERROR(gckHARDWARE_Flush(
+ hardware,
+ flush,
+ buffer,
+ &flushBytes
+ ));
+
+ /* Advance to next command. */
+ buffer = (gctUINT8_PTR)buffer + flushBytes;
/* Set the hardware event in the command queue. */
- gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
- buffer,
- id,
- Event->queues[id].source,
- &bytes));
+ gcmkONERROR(gckHARDWARE_Event(
+ hardware,
+ buffer,
+ id,
+ Event->queues[id].source,
+ &bytes
+ ));
+
+ /* Advance to next command. */
+ buffer = (gctUINT8_PTR)buffer + bytes;
/* Execute the hardware event. */
- gcmkONERROR(gckCOMMAND_Execute(command, bytes));
+ gcmkONERROR(gckCOMMAND_Execute(command, executeBytes));
#endif
}