1 /****************************************************************************
3 * Copyright (C) 2005 - 2014 by Vivante Corp.
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.
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.
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.
19 *****************************************************************************/
23 #include "gc_hal_kernel.h"
24 #include "gc_hal_kernel_context.h"
27 * -----------------------
28 * HARDWARE STATE RECORDER
29 * -----------------------
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'
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.
40 * == Commit 0 ====================================================================
46 * Mirror Buffer 0 <- Context Buffer 0 + Command Buffer 0
48 * == Commit 1 ====================================================================
52 * Mirror Buffer 1 <- Command buffer 1 + Mirror Buffer 0
54 * == Commit 2 ====================================================================
56 * Context Buffer 2 (optional)
60 * Mirror Buffer 2 <- Command buffer 2 + Context Buffer 2 + Mirror Buffer 1
62 * == Commit N ====================================================================
64 * For Commit N, these buffers are needed to reproduce hardware's behavior in
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.
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.
77 #define gcdNUM_RECORDS 6
79 typedef struct _gcsPARSER_HANDLER * gckPARSER_HANDLER;
83 IN gckPARSER_HANDLER Handler,
88 typedef struct _gcsPARSER_HANDLER
93 HandlerFunction function;
97 typedef struct _gcsPARSER * gckPARSER;
98 typedef struct _gcsPARSER
100 gctUINT8_PTR currentCmdBufferAddr;
102 /* Current command. */
109 gctUINT32 cmdRectCount;
115 /* Callback used by parser to handle a command. */
116 gckPARSER_HANDLER commandHandler;
120 typedef struct _gcsMIRROR
122 gctUINT32_PTR logical[gcdNUM_RECORDS];
124 gcsSTATE_MAP_PTR map;
125 gctUINT32 stateCount;
129 typedef struct _gcsDELTA
131 gctUINT64 commitStamp;
132 gctUINT32_PTR command;
133 gctUINT32 commandBytes;
134 gctUINT32_PTR context;
135 gctUINT32 contextBytes;
139 typedef struct _gcsRECORDER
143 gcsDELTA deltas[gcdNUM_RECORDS];
145 /* Index of current record. */
148 /* Number of records. */
151 /* Plugin used by gckPARSER. */
152 gcsPARSER_HANDLER recorderHandler;
158 /******************************************************************************\
159 ***************************** Command Buffer Parser ****************************
160 \******************************************************************************/
163 ** Command buffer parser checks command buffer in FE's view to make sure there
164 ** is no format error.
166 ** Parser provide a callback mechnisam, so plug-in can be added to implement
172 IN OUT gckPARSER Parser
176 gctUINT32_PTR data = (gctUINT32_PTR)Parser->currentCmdBufferAddr;
177 gctUINT32 cmdAddr = Parser->cmdAddr;
179 if (Parser->commandHandler == gcvNULL
180 || Parser->commandHandler->cmd != 0x01
183 /* No handler for this command. */
187 for (i = 0; i < Parser->cmdSize; i++)
189 Parser->commandHandler->function(Parser->commandHandler, cmdAddr, *data);
191 /* Advance to next state. */
199 IN OUT gckPARSER Parser
202 gctUINT32 * buffer = (gctUINT32 *)Parser->currentCmdBufferAddr;
204 gctUINT16 cmdRectCount;
205 gctUINT16 cmdDataCount;
207 Parser->hi = buffer[0];
208 Parser->lo = buffer[1];
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;
213 switch (Parser->cmdOpcode)
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)
221 Parser->cmdSize = 1024;
223 Parser->skip = (Parser->cmdSize & 0x1) ? 0 : 1;
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)))))) );
228 Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 4;
229 Parser->skipCount = Parser->cmdSize + Parser->skip;
234 Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
239 Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
244 Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
249 Parser->cmdAddr = 0x0F16;
250 Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
255 Parser->cmdAddr = 0x0F06;
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)))))) );
260 Parser->skipCount = gcmALIGN(Parser->cmdSize, 2)
262 + gcmALIGN(cmdDataCount, 2);
264 Parser->cmdRectCount = cmdRectCount;
268 Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
269 Parser->skipCount = 0;
273 Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
274 Parser->skipCount = 0;
278 /* Unknown command is a risk. */
279 Parser->allow = gcvFALSE;
286 IN OUT gckPARSER Parser
289 switch(Parser->cmdOpcode)
292 _HandleLoadState(Parser);
304 /* Advance to next command. */
305 Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr
306 + (Parser->skipCount << 2);
312 IN gctUINT8_PTR Buffer,
316 gckPARSER parser = Parser;
317 gctUINT8_PTR end = (gctUINT8_PTR)Buffer + Bytes;
319 /* Initialize parser. */
320 parser->currentCmdBufferAddr = (gctUINT8_PTR)Buffer;
322 parser->allow = gcvTRUE;
324 /* Go through command buffer until reaching the end
325 ** or meeting an error. */
330 _ParseCommand(parser);
332 while ((parser->currentCmdBufferAddr < end) && (parser->allow == gcvTRUE));
334 if (parser->allow == gcvFALSE)
336 /* Error detected. */
337 return gcvSTATUS_NOT_SUPPORTED;
343 /*******************************************************************************
345 ** gckPARSER_RegisterCommandHandler
347 ** Register a command handler which will be called when parser get a command.
351 gckPARSER_RegisterCommandHandler(
353 IN gckPARSER_HANDLER Handler
356 Parser->commandHandler = Handler;
364 IN gckPARSER_HANDLER Handler,
365 OUT gckPARSER * Parser
371 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsPARSER), (gctPOINTER *)&pointer));
373 /* Put it here temp, should have a more general plug-in mechnisam. */
374 pointer->commandHandler = Handler;
390 gcmkOS_SAFE_FREE(Os, Parser);
393 /******************************************************************************\
394 **************************** Hardware States Recorder **************************
395 \******************************************************************************/
399 IN gckPARSER_HANDLER Handler,
404 gcmkVERIFY_OK(gckRECORDER_UpdateMirror(Handler->private, Addr, Data));
414 return gcdNUM_RECORDS - 1;
425 return (Index + 1) % gcdNUM_RECORDS;
429 gckRECORDER_Construct(
431 IN gckHARDWARE Hardware,
432 OUT gckRECORDER * Recorder
436 gckCONTEXT context = gcvNULL;
437 gckRECORDER recorder = gcvNULL;
440 gctBOOL virtualCommandBuffer = Hardware->kernel->virtualCommandBuffer;
442 /* TODO: We only need context buffer and state map, it should be able to get without construct a
444 ** Now it is leaked, since we can't free it when command buffer is gone.
447 /* MMU is not ready now. */
448 Hardware->kernel->virtualCommandBuffer = gcvFALSE;
450 gcmkONERROR(gckCONTEXT_Construct(Os, Hardware, 0, &context));
453 Hardware->kernel->virtualCommandBuffer = virtualCommandBuffer;
455 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsRECORDER), (gctPOINTER *)&recorder));
457 gckOS_ZeroMemory(recorder, gcmSIZEOF(gcsRECORDER));
459 /* Copy state map. */
460 recorder->mirror.stateCount = context->stateCount;
462 mapSize = context->stateCount * gcmSIZEOF(gcsSTATE_MAP);
464 gcmkONERROR(gckOS_Allocate(Os, mapSize, (gctPOINTER *)&recorder->mirror.map));
466 gckOS_MemCopy(recorder->mirror.map, context->map, mapSize);
468 /* Copy context buffer. */
469 recorder->mirror.bytes = context->totalSize;
471 for (i = 0; i < gcdNUM_RECORDS; i++)
473 gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->mirror.logical[i]));
474 gckOS_MemCopy(recorder->mirror.logical[i], context->buffer->logical, context->totalSize);
477 for (i = 0; i < gcdNUM_RECORDS; i++)
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));
487 /* Initialize Parser plugin. */
488 recorder->recorderHandler.cmd = 0x01;
489 recorder->recorderHandler.private = recorder;
490 recorder->recorderHandler.function = _RecodeState;
492 gcmkONERROR(gckPARSER_Construct(Os, &recorder->recorderHandler, &recorder->parser));
496 *Recorder = recorder;
503 gckRECORDER_Destory(Os, recorder);
512 IN gckRECORDER Recorder
517 if (Recorder->mirror.map)
519 gcmkOS_SAFE_FREE(Os, Recorder->mirror.map);
522 for (i = 0; i < gcdNUM_RECORDS; i++)
524 if (Recorder->mirror.logical[i])
526 gcmkOS_SAFE_FREE(Os, Recorder->mirror.logical[i]);
530 for (i = 0; i < gcdNUM_RECORDS; i++)
532 if (Recorder->deltas[i].command)
534 gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].command);
537 if (Recorder->deltas[i].context)
539 gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].context);
543 if (Recorder->parser)
545 gckPARSER_Destroy(Os, Recorder->parser);
548 gcmkOS_SAFE_FREE(Os, Recorder);
554 gckRECORDER_UpdateMirror(
555 IN gckRECORDER Recorder,
561 gcsSTATE_MAP_PTR map = Recorder->mirror.map;
562 gctUINT32_PTR buffer = Recorder->mirror.logical[Recorder->index];
564 if (State >= Recorder->mirror.stateCount)
566 /* Ignore them just like HW does. */
570 index = map[State].index;
574 buffer[index] = Data;
581 gckRECORDER_AdvanceIndex(
582 IN gckRECORDER Recorder,
583 IN gctUINT64 CommitStamp
586 /* Get next record. */
587 gctUINT next = (Recorder->index + 1) % gcdNUM_RECORDS;
589 /* Record stamp of this commit. */
590 Recorder->deltas[Recorder->index].commitStamp = CommitStamp;
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);
596 /* Advance to next record. */
597 Recorder->index = next;
599 Recorder->num = gcmMIN(Recorder->num + 1, gcdNUM_RECORDS - 1);
603 Recorder->deltas[Recorder->index].commandBytes = 0;
604 Recorder->deltas[Recorder->index].contextBytes = 0;
609 IN gckRECORDER Recorder,
610 IN gctUINT8_PTR CommandBuffer,
611 IN gctUINT32 CommandBytes,
612 IN gctUINT8_PTR ContextBuffer,
613 IN gctUINT32 ContextBytes
616 gcsDELTA * delta = &Recorder->deltas[Recorder->index];
618 if (CommandBytes != 0xFFFFFFFF)
620 gckPARSER_Parse(Recorder->parser, CommandBuffer, CommandBytes);
621 gckOS_MemCopy(delta->command, CommandBuffer, CommandBytes);
622 delta->commandBytes = CommandBytes;
625 if (ContextBytes != 0xFFFFFFFF)
627 gckPARSER_Parse(Recorder->parser, ContextBuffer, ContextBytes);
628 gckOS_MemCopy(delta->context, ContextBuffer, ContextBytes);
629 delta->contextBytes = ContextBytes;
635 IN gckRECORDER Recorder
638 gctUINT last = Recorder->index;
641 gcsMIRROR *mirror = &Recorder->mirror;
643 gckOS os = Recorder->os;
645 for (i = 0; i < Recorder->num; i++)
647 last = _Previous(last);
650 for (i = 0; i < Recorder->num; i++)
652 delta = &Recorder->deltas[last];
655 gcmkPRINT("#[commit %llu]", delta->commitStamp);
657 if (delta->commitStamp)
659 previous = _Previous(last);
661 gcmkPRINT("#[mirror]");
662 gckOS_DumpBuffer(os, mirror->logical[previous], mirror->bytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE);
663 gcmkPRINT("@[kernel.execute]");
666 if (delta->contextBytes)
668 gckOS_DumpBuffer(os, delta->context, delta->contextBytes, gceDUMP_BUFFER_CONTEXT, gcvTRUE);
669 gcmkPRINT("@[kernel.execute]");
672 gckOS_DumpBuffer(os, delta->command, delta->commandBytes, gceDUMP_BUFFER_USER, gcvTRUE);
673 gcmkPRINT("@[kernel.execute]");