/*******************************************************************************
**
**	_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;
}
Example #2
0
/*
** 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, &reg_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, &reg_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;
}