]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / kernel / arch / gc_hal_kernel_recorder.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal.h"
23 #include "gc_hal_kernel.h"
24 #include "gc_hal_kernel_context.h"
25
26 /*
27  *                          -----------------------
28  *                          HARDWARE STATE RECORDER
29  *                          -----------------------
30  *
31  * State mirror buffer is used to 'mirror' hardware states since hardware
32  * states can't be dumpped. It is a context buffer which stores 'global'
33  * context.
34  *
35  * For each commit, state recorder
36  * 1) Records context buffer (if there is) and command buffers in this commit.
37  * 2) Parse those buffers to estimate the state changed.
38  * 3) Stores result to a mirror buffer.
39  *
40  * == Commit 0 ====================================================================
41  *
42  *      Context Buffer 0
43  *
44  *      Command Buffer 0
45  *
46  *      Mirror Buffer  0  <- Context Buffer 0 + Command Buffer 0
47  *
48  * == Commit 1 ====================================================================
49  *
50  *      Command Buffer 1
51  *
52  *      Mirror Buffer  1  <- Command buffer 1 + Mirror Buffer 0
53  *
54  * == Commit 2 ====================================================================
55  *
56  *      Context Buffer 2 (optional)
57  *
58  *      Command Buffer 2
59  *
60  *      Mirror  Buffer 2  <- Command buffer 2 + Context Buffer 2 + Mirror Buffer 1
61  *
62  * == Commit N ====================================================================
63  *
64  * For Commit N, these buffers are needed to reproduce hardware's behavior in
65  * this commit.
66  *
67  *  Mirror  Buffer [N - 1] : State Mirror accumlated by past commits,
68  *                           which is used to restore hardware state.
69  *  Context Buffer [N]     :
70  *  Command Buffer [N]     : Command buffer executed by hardware in this commit.
71  *
72  *  If sequence of states programming matters, hardware's behavior can't be reproduced,
73  *  but the state values stored in mirror buffer are assuring.
74  */
75
76 /* Queue size. */
77 #define gcdNUM_RECORDS  6
78
79 typedef struct _gcsPARSER_HANDLER * gckPARSER_HANDLER;
80
81 typedef void
82 (*HandlerFunction)(
83     IN gckPARSER_HANDLER Handler,
84     IN gctUINT32 Addr,
85     IN gctUINT32 Data
86     );
87
88 typedef struct _gcsPARSER_HANDLER
89 {
90     gctUINT32           type;
91     gctUINT32           cmd;
92     gctPOINTER          private;
93     HandlerFunction     function;
94 }
95 gcsPARSER_HANDLER;
96
97 typedef struct _gcsPARSER * gckPARSER;
98 typedef struct _gcsPARSER
99 {
100     gctUINT8_PTR        currentCmdBufferAddr;
101
102     /* Current command. */
103     gctUINT32           lo;
104     gctUINT32           hi;
105
106     gctUINT8            cmdOpcode;
107     gctUINT16           cmdAddr;
108     gctUINT32           cmdSize;
109     gctUINT32           cmdRectCount;
110     gctUINT8            skip;
111     gctUINT32           skipCount;
112
113     gctBOOL             allow;
114
115     /* Callback used by parser to handle a command. */
116     gckPARSER_HANDLER   commandHandler;
117 }
118 gcsPARSER;
119
120 typedef struct _gcsMIRROR
121 {
122     gctUINT32_PTR       logical[gcdNUM_RECORDS];
123     gctUINT32           bytes;
124     gcsSTATE_MAP_PTR    map;
125     gctUINT32           stateCount;
126 }
127 gcsMIRROR;
128
129 typedef struct _gcsDELTA
130 {
131     gctUINT64           commitStamp;
132     gctUINT32_PTR       command;
133     gctUINT32           commandBytes;
134     gctUINT32_PTR       context;
135     gctUINT32           contextBytes;
136 }
137 gcsDELTA;
138
139 typedef struct _gcsRECORDER
140 {
141     gckOS               os;
142     gcsMIRROR           mirror;
143     gcsDELTA            deltas[gcdNUM_RECORDS];
144
145     /* Index of current record. */
146     gctUINT             index;
147
148     /* Number of records. */
149     gctUINT             num;
150
151     /* Plugin used by gckPARSER. */
152     gcsPARSER_HANDLER   recorderHandler;
153     gckPARSER           parser;
154 }
155 gcsRECORDER;
156
157
158 /******************************************************************************\
159 ***************************** Command Buffer Parser ****************************
160 \******************************************************************************/
161
162 /*
163 ** Command buffer parser checks command buffer in FE's view to make sure there
164 ** is no format error.
165 **
166 ** Parser provide a callback mechnisam, so plug-in can be added to implement
167 ** other functions.
168 */
169
170 static void
171 _HandleLoadState(
172     IN OUT gckPARSER Parser
173     )
174 {
175     gctUINT i;
176     gctUINT32_PTR data = (gctUINT32_PTR)Parser->currentCmdBufferAddr;
177     gctUINT32 cmdAddr = Parser->cmdAddr;
178
179     if (Parser->commandHandler == gcvNULL
180      || Parser->commandHandler->cmd != 0x01
181     )
182     {
183         /* No handler for this command. */
184         return;
185     }
186
187     for (i = 0; i < Parser->cmdSize; i++)
188     {
189         Parser->commandHandler->function(Parser->commandHandler, cmdAddr, *data);
190
191         /* Advance to next state. */
192         cmdAddr++;
193         data++;
194     }
195 }
196
197 static void
198 _GetCommand(
199     IN OUT gckPARSER Parser
200     )
201 {
202     gctUINT32 * buffer = (gctUINT32 *)Parser->currentCmdBufferAddr;
203
204     gctUINT16 cmdRectCount;
205     gctUINT16 cmdDataCount;
206
207     Parser->hi = buffer[0];
208     Parser->lo = buffer[1];
209
210     Parser->cmdOpcode = (((((gctUINT32) (Parser->hi)) >> (0 ? 31:27)) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) );
211     Parser->cmdRectCount = 1;
212
213     switch (Parser->cmdOpcode)
214     {
215     case 0x01:
216         /* Extract count. */
217         Parser->cmdSize = (((((gctUINT32) (Parser->hi)) >> (0 ? 25:16)) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1)))))) );
218         if (Parser->cmdSize == 0)
219         {
220             /* 0 means 1024. */
221             Parser->cmdSize = 1024;
222         }
223         Parser->skip = (Parser->cmdSize & 0x1) ? 0 : 1;
224
225         /* Extract address. */
226         Parser->cmdAddr = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) );
227
228         Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 4;
229         Parser->skipCount = Parser->cmdSize + Parser->skip;
230         break;
231
232      case 0x05:
233         Parser->cmdSize   = 4;
234         Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
235         break;
236
237     case 0x06:
238         Parser->cmdSize   = 5;
239         Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
240         break;
241
242     case 0x0C:
243         Parser->cmdSize   = 3;
244         Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
245         break;
246
247     case 0x09:
248         Parser->cmdSize   = 2;
249         Parser->cmdAddr   = 0x0F16;
250         Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
251         break;
252
253      case 0x04:
254         Parser->cmdSize = 1;
255         Parser->cmdAddr = 0x0F06;
256
257         cmdRectCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) );
258         cmdDataCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 26:16)) & ((gctUINT32) ((((1 ? 26:16) - (0 ? 26:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:16) - (0 ? 26:16) + 1)))))) );
259
260         Parser->skipCount = gcmALIGN(Parser->cmdSize, 2)
261                           + cmdRectCount * 2
262                           + gcmALIGN(cmdDataCount, 2);
263
264         Parser->cmdRectCount = cmdRectCount;
265         break;
266
267     case 0x03:
268         Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
269         Parser->skipCount = 0;
270         break;
271
272     case 0x02:
273         Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
274         Parser->skipCount = 0;
275         break;
276
277     default:
278         /* Unknown command is a risk. */
279         Parser->allow = gcvFALSE;
280         break;
281     }
282 }
283
284 static void
285 _ParseCommand(
286     IN OUT gckPARSER Parser
287     )
288 {
289     switch(Parser->cmdOpcode)
290     {
291     case 0x01:
292         _HandleLoadState(Parser);
293         break;
294     case 0x05:
295     case 0x06:
296     case 0x0C:
297         break;
298     case 0x04:
299         break;
300     default:
301         break;
302     }
303
304     /* Advance to next command. */
305     Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr
306                                  + (Parser->skipCount << 2);
307 }
308
309 gceSTATUS
310 gckPARSER_Parse(
311     IN gckPARSER Parser,
312     IN gctUINT8_PTR Buffer,
313     IN gctUINT32 Bytes
314     )
315 {
316     gckPARSER parser = Parser;
317     gctUINT8_PTR end = (gctUINT8_PTR)Buffer + Bytes;
318
319     /* Initialize parser. */
320     parser->currentCmdBufferAddr = (gctUINT8_PTR)Buffer;
321     parser->skip = 0;
322     parser->allow = gcvTRUE;
323
324     /* Go through command buffer until reaching the end
325     ** or meeting an error. */
326     do
327     {
328         _GetCommand(parser);
329
330         _ParseCommand(parser);
331     }
332     while ((parser->currentCmdBufferAddr < end) && (parser->allow == gcvTRUE));
333
334     if (parser->allow == gcvFALSE)
335     {
336         /* Error detected. */
337         return gcvSTATUS_NOT_SUPPORTED;
338     }
339
340     return gcvSTATUS_OK;
341 }
342
343 /*******************************************************************************
344 **
345 **  gckPARSER_RegisterCommandHandler
346 **
347 **  Register a command handler which will be called when parser get a command.
348 **
349 */
350 gceSTATUS
351 gckPARSER_RegisterCommandHandler(
352     IN gckPARSER Parser,
353     IN gckPARSER_HANDLER Handler
354     )
355 {
356     Parser->commandHandler = Handler;
357
358     return gcvSTATUS_OK;
359 }
360
361 gceSTATUS
362 gckPARSER_Construct(
363     IN gckOS Os,
364     IN gckPARSER_HANDLER Handler,
365     OUT gckPARSER * Parser
366     )
367 {
368     gceSTATUS status;
369     gckPARSER pointer;
370
371     gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsPARSER), (gctPOINTER *)&pointer));
372
373     /* Put it here temp, should have a more general plug-in mechnisam. */
374     pointer->commandHandler = Handler;
375
376     *Parser = pointer;
377
378     return gcvSTATUS_OK;
379
380 OnError:
381     return status;
382 }
383
384 void
385 gckPARSER_Destroy(
386     IN gckOS Os,
387     IN gckPARSER Parser
388     )
389 {
390     gcmkOS_SAFE_FREE(Os, Parser);
391 }
392
393 /******************************************************************************\
394 **************************** Hardware States Recorder **************************
395 \******************************************************************************/
396
397 static void
398 _RecodeState(
399     IN gckPARSER_HANDLER Handler,
400     IN gctUINT32 Addr,
401     IN gctUINT32 Data
402     )
403 {
404     gcmkVERIFY_OK(gckRECORDER_UpdateMirror(Handler->private, Addr, Data));
405 }
406
407 static gctUINT
408 _Previous(
409     IN gctUINT Index
410     )
411 {
412     if (Index == 0)
413     {
414         return gcdNUM_RECORDS - 1;
415     }
416
417     return Index - 1;
418 }
419
420 static gctUINT
421 _Next(
422     IN gctUINT Index
423     )
424 {
425     return (Index + 1) % gcdNUM_RECORDS;
426 }
427
428 gceSTATUS
429 gckRECORDER_Construct(
430     IN gckOS Os,
431     IN gckHARDWARE Hardware,
432     OUT gckRECORDER * Recorder
433     )
434 {
435     gceSTATUS status;
436     gckCONTEXT context = gcvNULL;
437     gckRECORDER recorder = gcvNULL;
438     gctUINT32 mapSize;
439     gctUINT i;
440     gctBOOL virtualCommandBuffer = Hardware->kernel->virtualCommandBuffer;
441
442     /* TODO: We only need context buffer and state map, it should be able to get without construct a
443     ** new context.
444     ** Now it is leaked, since we can't free it when command buffer is gone.
445     */
446
447     /* MMU is not ready now. */
448     Hardware->kernel->virtualCommandBuffer = gcvFALSE;
449
450     gcmkONERROR(gckCONTEXT_Construct(Os, Hardware, 0, &context));
451
452     /* Restore. */
453     Hardware->kernel->virtualCommandBuffer = virtualCommandBuffer;
454
455     gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsRECORDER), (gctPOINTER *)&recorder));
456
457     gckOS_ZeroMemory(recorder, gcmSIZEOF(gcsRECORDER));
458
459     /* Copy state map. */
460     recorder->mirror.stateCount = context->stateCount;
461
462     mapSize = context->stateCount * gcmSIZEOF(gcsSTATE_MAP);
463
464     gcmkONERROR(gckOS_Allocate(Os, mapSize, (gctPOINTER *)&recorder->mirror.map));
465
466     gckOS_MemCopy(recorder->mirror.map, context->map, mapSize);
467
468     /* Copy context buffer. */
469     recorder->mirror.bytes = context->totalSize;
470
471     for (i = 0; i < gcdNUM_RECORDS; i++)
472     {
473         gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->mirror.logical[i]));
474         gckOS_MemCopy(recorder->mirror.logical[i], context->buffer->logical, context->totalSize);
475     }
476
477     for (i = 0; i < gcdNUM_RECORDS; i++)
478     {
479         /* TODO : Optimize size. */
480         gcmkONERROR(gckOS_Allocate(Os, gcdCMD_BUFFER_SIZE, (gctPOINTER *)&recorder->deltas[i].command));
481         gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->deltas[i].context));
482     }
483
484     recorder->index = 0;
485     recorder->num   = 0;
486
487     /* Initialize Parser plugin. */
488     recorder->recorderHandler.cmd = 0x01;
489     recorder->recorderHandler.private = recorder;
490     recorder->recorderHandler.function = _RecodeState;
491
492     gcmkONERROR(gckPARSER_Construct(Os, &recorder->recorderHandler, &recorder->parser));
493
494     recorder->os = Os;
495
496     *Recorder = recorder;
497
498     return gcvSTATUS_OK;
499
500 OnError:
501     if (recorder)
502     {
503         gckRECORDER_Destory(Os, recorder);
504     }
505
506     return status;
507 }
508
509 gceSTATUS
510 gckRECORDER_Destory(
511     IN gckOS Os,
512     IN gckRECORDER Recorder
513     )
514 {
515     gctUINT i;
516
517     if (Recorder->mirror.map)
518     {
519         gcmkOS_SAFE_FREE(Os, Recorder->mirror.map);
520     }
521
522     for (i = 0; i < gcdNUM_RECORDS; i++)
523     {
524         if (Recorder->mirror.logical[i])
525         {
526             gcmkOS_SAFE_FREE(Os, Recorder->mirror.logical[i]);
527         }
528     }
529
530     for (i = 0; i < gcdNUM_RECORDS; i++)
531     {
532         if (Recorder->deltas[i].command)
533         {
534             gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].command);
535         }
536
537         if (Recorder->deltas[i].context)
538         {
539             gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].context);
540         }
541     }
542
543     if (Recorder->parser)
544     {
545         gckPARSER_Destroy(Os, Recorder->parser);
546     }
547
548     gcmkOS_SAFE_FREE(Os, Recorder);
549
550     return gcvSTATUS_OK;
551 }
552
553 gceSTATUS
554 gckRECORDER_UpdateMirror(
555     IN gckRECORDER Recorder,
556     IN gctUINT32 State,
557     IN gctUINT32 Data
558     )
559 {
560     gctUINT32 index;
561     gcsSTATE_MAP_PTR map = Recorder->mirror.map;
562     gctUINT32_PTR buffer = Recorder->mirror.logical[Recorder->index];
563
564     if (State >= Recorder->mirror.stateCount)
565     {
566         /* Ignore them just like HW does. */
567         return gcvSTATUS_OK;
568     }
569
570     index = map[State].index;
571
572     if (index)
573     {
574         buffer[index] = Data;
575     }
576
577     return gcvSTATUS_OK;
578 }
579
580 void
581 gckRECORDER_AdvanceIndex(
582     IN gckRECORDER Recorder,
583     IN gctUINT64 CommitStamp
584     )
585 {
586     /* Get next record. */
587     gctUINT next = (Recorder->index + 1) % gcdNUM_RECORDS;
588
589     /* Record stamp of this commit. */
590     Recorder->deltas[Recorder->index].commitStamp = CommitStamp;
591
592     /* Mirror of next record is mirror of this record and delta in next record. */
593     gckOS_MemCopy(Recorder->mirror.logical[next],
594         Recorder->mirror.logical[Recorder->index], Recorder->mirror.bytes);
595
596     /* Advance to next record. */
597     Recorder->index = next;
598
599     Recorder->num = gcmMIN(Recorder->num + 1, gcdNUM_RECORDS - 1);
600
601
602     /* Reset delta. */
603     Recorder->deltas[Recorder->index].commandBytes = 0;
604     Recorder->deltas[Recorder->index].contextBytes = 0;
605 }
606
607 void
608 gckRECORDER_Record(
609     IN gckRECORDER Recorder,
610     IN gctUINT8_PTR CommandBuffer,
611     IN gctUINT32 CommandBytes,
612     IN gctUINT8_PTR ContextBuffer,
613     IN gctUINT32 ContextBytes
614     )
615 {
616     gcsDELTA * delta = &Recorder->deltas[Recorder->index];
617
618     if (CommandBytes != 0xFFFFFFFF)
619     {
620         gckPARSER_Parse(Recorder->parser, CommandBuffer, CommandBytes);
621         gckOS_MemCopy(delta->command, CommandBuffer, CommandBytes);
622         delta->commandBytes = CommandBytes;
623     }
624
625     if (ContextBytes != 0xFFFFFFFF)
626     {
627         gckPARSER_Parse(Recorder->parser, ContextBuffer, ContextBytes);
628         gckOS_MemCopy(delta->context, ContextBuffer, ContextBytes);
629         delta->contextBytes = ContextBytes;
630     }
631 }
632
633 void
634 gckRECORDER_Dump(
635     IN gckRECORDER Recorder
636     )
637 {
638     gctUINT last = Recorder->index;
639     gctUINT previous;
640     gctUINT i;
641     gcsMIRROR *mirror = &Recorder->mirror;
642     gcsDELTA *delta;
643     gckOS os = Recorder->os;
644
645     for (i = 0; i < Recorder->num; i++)
646     {
647         last = _Previous(last);
648     }
649
650     for (i = 0; i < Recorder->num; i++)
651     {
652         delta = &Recorder->deltas[last];
653
654         /* Dump record */
655         gcmkPRINT("#[commit %llu]", delta->commitStamp);
656
657         if (delta->commitStamp)
658         {
659             previous = _Previous(last);
660
661             gcmkPRINT("#[mirror]");
662             gckOS_DumpBuffer(os, mirror->logical[previous], mirror->bytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE);
663             gcmkPRINT("@[kernel.execute]");
664         }
665
666         if (delta->contextBytes)
667         {
668             gckOS_DumpBuffer(os, delta->context, delta->contextBytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE);
669             gcmkPRINT("@[kernel.execute]");
670         }
671
672         gckOS_DumpBuffer(os, delta->command, delta->commandBytes, gceDUMP_BUFFER_USER, gcvTRUE);
673         gcmkPRINT("@[kernel.execute]");
674
675         last = _Next(last);
676     }
677 }
678
679