/*******************************************************************************
**
**  gckKERNEL_AllocateLinearMemory
**
**  Function walks all required memory pools and allocates the requested
**  amount of video memory.
**
**  INPUT:
**
**      gckKERNEL Kernel
**          Pointer to an gckKERNEL object.
**
**      gcePOOL * Pool
**          Pointer the desired memory pool.
**
**      gctSIZE_T Bytes
**          Number of bytes to allocate.
**
**      gctSIZE_T Alignment
**          Required buffer alignment.
**
**      gceSURF_TYPE Type
**          Surface type.
**
**  OUTPUT:
**
**      gcePOOL * Pool
**          Pointer to the actual pool where the memory was allocated.
**
**      gcuVIDMEM_NODE_PTR * Node
**          Allocated node.
*/
gceSTATUS
gckKERNEL_AllocateLinearMemory(
    IN gckKERNEL Kernel,
    IN OUT gcePOOL * Pool,
    IN gctSIZE_T Bytes,
    IN gctSIZE_T Alignment,
    IN gceSURF_TYPE Type,
    OUT gcuVIDMEM_NODE_PTR * Node
    )
{
    gcePOOL pool;
    gceSTATUS status;
    gckVIDMEM videoMemory;

    /* Get initial pool. */
    switch (pool = *Pool)
    {
    case gcvPOOL_DEFAULT:
    case gcvPOOL_LOCAL:
        pool = gcvPOOL_LOCAL_INTERNAL;
        break;

    case gcvPOOL_UNIFIED:
        pool = gcvPOOL_SYSTEM;
        break;

    default:
        break;
    }

    do
    {
        /* Verify the number of bytes to allocate. */
        if (Bytes == 0)
        {
            status = gcvSTATUS_INVALID_ARGUMENT;
            break;
        }

        if (pool == gcvPOOL_VIRTUAL)
        {
            /* Create a gcuVIDMEM_NODE for virtual memory. */
            gcmkERR_BREAK(gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node));

            /* Success. */
            break;
        }

        else
        {
            /* Get pointer to gckVIDMEM object for pool. */
            status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);

            if (status == gcvSTATUS_OK)
            {
                /* Allocate memory. */
                status = gckVIDMEM_AllocateLinear(Kernel,
                                                  videoMemory,
                                                  Bytes,
                                                  Alignment,
                                                  Type,
                                                  Node);

                if (status == gcvSTATUS_OK)
                {
                    /* Memory allocated. */
                    break;
                }
            }
        }

        if (pool == gcvPOOL_LOCAL_INTERNAL)
        {
            /* Advance to external memory. */
            pool = gcvPOOL_LOCAL_EXTERNAL;
        }
        else if (pool == gcvPOOL_LOCAL_EXTERNAL)
        {
            /* Advance to contiguous system memory. */
            pool = gcvPOOL_SYSTEM;
        }
        else if (pool == gcvPOOL_SYSTEM)
        {
            /* Advance to virtual memory. */
            pool = gcvPOOL_VIRTUAL;
        }
        else
        {
            /* Out of pools. */
            break;
        }
    }
    /* Loop only for multiple selection pools. */
    while ((*Pool == gcvPOOL_DEFAULT)
    ||     (*Pool == gcvPOOL_LOCAL)
    ||     (*Pool == gcvPOOL_UNIFIED)
    );

    if (gcmIS_SUCCESS(status))
    {
        /* Return pool used for allocation. */
        *Pool = pool;
    }

    /* Return status. */
    return status;
}
/*******************************************************************************
**
**	_AllocateMemory
**
**	Private function to walk all required memory pools to allocate the requested
**	amount of video memory.
**
**	INPUT:
**
**		gckKERNEL Kernel
**			Pointer to an gckKERNEL object.
**
**		gcsHAL_INTERFACE * Interface
**			Pointer to a gcsHAL_INTERFACE structure that defines the command to
**			be dispatched.
**
**	OUTPUT:
**
**		gcsHAL_INTERFACE * Interface
**			Pointer to a gcsHAL_INTERFACE structure that receives any data to be
**			returned.
*/
static gceSTATUS
_AllocateMemory(
	IN gckKERNEL Kernel,
	IN OUT gcePOOL * Pool,
	IN gctSIZE_T Bytes,
	IN gctSIZE_T Alignment,
	IN gceSURF_TYPE Type,
#ifdef __QNXNTO__
	IN gctHANDLE Handle,
#endif
	OUT gcuVIDMEM_NODE_PTR * Node
	)
{
	gcePOOL pool;
	gceSTATUS status;
	gckVIDMEM videoMemory;

	gcmkVERIFY_ARGUMENT(Pool != gcvNULL);

	/* Get initial pool. */
	switch (pool = *Pool)
	{
	case gcvPOOL_DEFAULT:
	case gcvPOOL_LOCAL:
		pool = gcvPOOL_LOCAL_INTERNAL;
		break;

	case gcvPOOL_UNIFIED:
		pool = gcvPOOL_SYSTEM;
		break;

	default:
		break;
	}

	do
	{
		/* Verify the number of bytes to allocate. */
		if (Bytes == 0)
		{
			gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT);
		}

		if (pool == gcvPOOL_VIRTUAL)
		{
			/* Create a gcuVIDMEM_NODE for virtual memory. */
#ifdef __QNXNTO__
			gcmkERR_BREAK(
				gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Handle, Node));
#else
			gcmkERR_BREAK(
				gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node));
#endif

			/* Success. */
			break;
		}
		else if (pool == gcvPOOL_CONTIGUOUS)
		{
			/* Create a gcuVIDMEM_NODE for contiguous memory. */
#ifdef __QNXNTO__
			status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Handle, Node);
#else
			status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Node);
#endif
			if (gcmIS_SUCCESS(status))
			{
				/* Memory allocated. */
				break;
			}
		}
		else
		{
			/* Get pointer to gckVIDMEM object for pool. */
			status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);

			if (gcmIS_SUCCESS(status))
			{
				/* Allocate memory. */
				status = gckVIDMEM_AllocateLinear(videoMemory,
												  Bytes,
												  Alignment,
												  Type,
#ifdef __QNXNTO__
												  Handle,
#endif
												  Node);

				if (gcmIS_SUCCESS(status))
				{
					/* Memory allocated. */
					(*Node)->VidMem.pool = pool;
					break;
				}
			}
		}

		if (pool == gcvPOOL_LOCAL_INTERNAL)
		{
			/* Advance to external memory. */
			pool = gcvPOOL_LOCAL_EXTERNAL;
		}
		else
		if (pool == gcvPOOL_LOCAL_EXTERNAL)
		{
			/* Advance to contiguous system memory. */
			pool = gcvPOOL_SYSTEM;
		}
		else
		if (pool == gcvPOOL_SYSTEM)
		{
			/* Advance to contiguous memory. */
			pool = gcvPOOL_CONTIGUOUS;
		}
		else
		if ((pool == gcvPOOL_CONTIGUOUS)
		&&  (Type != gcvSURF_TILE_STATUS)
		)
		{
            static int count= 1;
			/* Advance to virtual memory. */
            if (count == 1)
            {
				gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
					"Try to allocate virtual memory!\n");
                count = 0;
            }
			pool = gcvPOOL_VIRTUAL;
		}
		else
		{
			/* Out of pools. */
			break;
		}
	}
	/* Loop only for multiple selection pools. */
	while ((*Pool == gcvPOOL_DEFAULT)
	||     (*Pool == gcvPOOL_LOCAL)
	||     (*Pool == gcvPOOL_UNIFIED)
	);

	if (gcmIS_SUCCESS(status))
	{
		/* Return pool used for allocation. */
		*Pool = pool;
	}

	/* Return status. */
	return status;
}