/******************************************************************************* ** ** _NewQueue ** ** Allocate a new command queue. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** OUTPUT: ** ** gckCOMMAND Command ** gckCOMMAND object has been updated with a new command queue. */ static gceSTATUS _NewQueue( IN OUT gckCOMMAND Command, IN gctBOOL Locking ) { gceSTATUS status; gctINT currentIndex, newIndex; gcmkHEADER_ARG("Command=0x%x Locking=%d", Command, Locking); /* Switch to the next command buffer. */ currentIndex = Command->index; newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES; /* Wait for availability. */ #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.waitsignal]"); #endif gcmkONERROR( gckOS_WaitSignal(Command->os, Command->queues[newIndex].signal, gcvINFINITE)); if (currentIndex >= 0) { /* Mark the command queue as available. */ gcmkONERROR(gckEVENT_Signal(Command->kernel->event, Command->queues[currentIndex].signal, gcvKERNEL_PIXEL, Locking)); } /* Update gckCOMMAND object with new command queue. */ Command->index = newIndex; Command->newQueue = gcvTRUE; Command->physical = Command->queues[newIndex].physical; Command->logical = Command->queues[newIndex].logical; Command->offset = 0; if (currentIndex >= 0) { /* Submit the event queue. */ Command->submit = gcvTRUE; } /* Success. */ gcmkFOOTER_ARG("Command->index=%d", Command->index); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
/* ** PM Thread Routine **/ static int threadRoutinePM(void *ctxt) { gckGALDEVICE device = (gckGALDEVICE) ctxt; gckHARDWARE hardware = device->kernels[gcvCORE_MAJOR]->hardware; gceCHIPPOWERSTATE state; for(;;) { /* wait for idle */ gcmkVERIFY_OK( gckOS_WaitSignal(device->os, hardware->powerOffSignal, gcvINFINITE)); /* We try to power off every 200 ms, until GPU is not idle */ do { if (device->killThread == gcvTRUE) { /* The daemon exits. */ while (!kthread_should_stop()) { gckOS_Delay(device->os, 1); } return 0; } gcmkVERIFY_OK( gckHARDWARE_SetPowerManagementState( hardware, gcvPOWER_OFF_TIMEOUT)); /* relax cpu 200 ms before retry */ gckOS_Delay(device->os, 200); gcmkVERIFY_OK( gckHARDWARE_QueryPowerManagementState(hardware, &state)); } while (state == gcvPOWER_IDLE); } }
/******************************************************************************* ** ** gckCOMMAND_Stall ** ** The calling thread will be suspended until the command queue has been ** completed. ** ** INPUT: ** ** gckCOMMAND Command ** Pointer to an gckCOMMAND object. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckCOMMAND_Stall( IN gckCOMMAND Command ) { gckOS os; gckHARDWARE hardware; gckEVENT event; gceSTATUS status; gctSIGNAL signal = gcvNULL; gcmkHEADER_ARG("Command=0x%x", Command); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); #if gcdNULL_DRIVER == 2 /* Do nothing with infinite hardware. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; #endif /* Extract the gckOS object pointer. */ os = Command->os; gcmkVERIFY_OBJECT(os, gcvOBJ_OS); /* Extract the gckHARDWARE object pointer. */ hardware = Command->kernel->hardware; gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); /* Extract the gckEVENT object pointer. */ event = Command->kernel->event; gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); /* Allocate the signal. */ gcmkONERROR( gckOS_CreateSignal(os, gcvTRUE, &signal)); /* Append the EVENT command to trigger the signal. */ gcmkONERROR(gckEVENT_Signal(event, signal, gcvKERNEL_PIXEL, gcvFALSE)); /* Submit the event queue. */ gcmkONERROR(gckEVENT_Submit(event, gcvTRUE, gcvFALSE)); #if gcdDUMP_COMMAND gcmkPRINT("@[kernel.stall]"); #endif if (status == gcvSTATUS_CHIP_NOT_READY) { /* Error. */ goto OnError; } do { /* Wait for the signal. */ status = gckOS_WaitSignal(os, signal, gcvINFINITE); if (status == gcvSTATUS_TIMEOUT) { #if gcdDEBUG gctUINT32 idle; /* IDLE */ gckOS_ReadRegister(Command->os, 0x0004, &idle); gcmkTRACE(gcvLEVEL_ERROR, "%s(%d): idle=%08x", __FUNCTION__, __LINE__, idle); gckOS_Log(_GFX_LOG_WARNING_, "%s : %d : idle register = 0x%08x \n", __FUNCTION__, __LINE__, idle); #endif #if MRVL_PRINT_CMD_BUFFER { gctUINT i; gctUINT32 idle; gctUINT32 intAck; gctUINT32 prevAddr = 0; gctUINT32 currAddr; gctBOOL changeDetected; changeDetected = gcvFALSE; /* IDLE */ gckOS_ReadRegister(Command->os, 0x0004, &idle); /* INT ACK */ gckOS_ReadRegister(Command->os, 0x0010, &intAck); /* DMA POS */ for (i = 0; i < 300; i += 1) { gckOS_ReadRegister(Command->os, 0x0664, &currAddr); if ((i > 0) && (prevAddr != currAddr)) { changeDetected = gcvTRUE; } prevAddr = currAddr; } gcmTRACE(0, "\n%s(%d):\n" " idle = 0x%08X\n" " int = 0x%08X\n" " dma = 0x%08X (change=%d)\n", __FUNCTION__, __LINE__, idle, intAck, currAddr, changeDetected ); _PrintCmdBuffer(Command, currAddr); _PrintLinkChain(); } #endif #if MRVL_LOW_POWER_MODE_DEBUG { int i = 0; printk(">>>>>>>>>>>>galDevice->kernel->kernelMSG\n"); printk("galDevice->kernel->msgLen=%d\n",Command->kernel->msgLen); for(i=0;i<Command->kernel->msgLen;i+=1024) { Command->kernel->kernelMSG[i+1023] = '\0'; printk("%s\n",(char*)Command->kernel->kernelMSG + i); } } #endif #ifdef __QNXNTO__ gctUINT32 reg_cmdbuf_fetch; gctUINT32 reg_intr; gcmkVERIFY_OK( gckOS_ReadRegister(Command->kernel->hardware->os, 0x0664, ®_cmdbuf_fetch)); if (idle == 0x7FFFFFFE) { /* * GPU is idle so there should not be pending interrupts. * Just double check. * * Note that reading interrupt register clears it. * That's why we don't read it in all cases. */ gcmkVERIFY_OK( gckOS_ReadRegister(Command->kernel->hardware->os, 0x10, ®_intr)); slogf( _SLOG_SETCODE(1, 0), _SLOG_CRITICAL, "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X, interrupt = 0x%X)", idle, reg_cmdbuf_fetch, reg_intr); } else { slogf( _SLOG_SETCODE(1, 0), _SLOG_CRITICAL, "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X)", idle, reg_cmdbuf_fetch); } #endif gcmkVERIFY_OK( gckOS_MemoryBarrier(os, gcvNULL)); } } while (gcmIS_ERROR(status)); /* Delete the signal. */ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Free the signal. */ if (signal != gcvNULL) { gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); } /* Return the status. */ gcmkFOOTER(); return status; }