Files
linux-legacy/drivers/mxc/amd-gpu/gsl_cmdstream.c

230 lines
6.6 KiB
C

/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include "mxc_kgsl.h"
#include "gsl.h"
#include "gsl_hal.h"
#include "gsl_cmdstream.h"
// functions
int kgsl_cmdstream_init(gsl_device_t *device)
{
return GSL_SUCCESS;
}
int kgsl_cmdstream_close(gsl_device_t *device)
{
return GSL_SUCCESS;
}
gsl_timestamp_t kgsl_cmdstream_readtimestamp0(gsl_deviceid_t device_id, gsl_timestamp_type_t type)
{
gsl_timestamp_t timestamp = -1;
gsl_device_t* device = &gsl_driver.device[device_id-1];
kgsl_log_write( KGSL_LOG_GROUP_COMMAND | KGSL_LOG_LEVEL_TRACE,
"--> gsl_timestamp_t kgsl_cmdstream_readtimestamp(gsl_deviceid_t device_id=%D gsl_timestamp_type_t type=%d)\n", device_id, type );
#if (defined(GSL_BLD_G12) && defined(IRQTHREAD_POLL))
complete_all(&device->irqthread_event);
#endif
if (type == GSL_TIMESTAMP_CONSUMED)
{
// start-of-pipeline timestamp
GSL_CMDSTREAM_GET_SOP_TIMESTAMP(device, (unsigned int*)&timestamp);
}
else if (type == GSL_TIMESTAMP_RETIRED)
{
// end-of-pipeline timestamp
GSL_CMDSTREAM_GET_EOP_TIMESTAMP(device, (unsigned int*)&timestamp);
}
rmb();
kgsl_log_write( KGSL_LOG_GROUP_COMMAND | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_ringbuffer_readtimestamp. Return value %d\n", timestamp );
return (timestamp);
}
//----------------------------------------------------------------------------
gsl_timestamp_t
kgsl_cmdstream_readtimestamp(gsl_deviceid_t device_id, gsl_timestamp_type_t type)
{
gsl_timestamp_t timestamp = -1;
mutex_lock(&gsl_driver.lock);
timestamp = kgsl_cmdstream_readtimestamp0(device_id, type);
mutex_unlock(&gsl_driver.lock);
return timestamp;
}
//----------------------------------------------------------------------------
int
kgsl_cmdstream_issueibcmds(gsl_deviceid_t device_id, int drawctxt_index, gpuaddr_t ibaddr, int sizedwords, gsl_timestamp_t *timestamp, unsigned int flags)
{
gsl_device_t* device = &gsl_driver.device[device_id-1];
int status = GSL_FAILURE;
mutex_lock(&gsl_driver.lock);
kgsl_device_active(device);
if (device->ftbl.cmdstream_issueibcmds)
{
status = device->ftbl.cmdstream_issueibcmds(device, drawctxt_index, ibaddr, sizedwords, timestamp, flags);
}
mutex_unlock(&gsl_driver.lock);
return status;
}
//----------------------------------------------------------------------------
int kgsl_cmdstream_waittimestamp(gsl_deviceid_t device_id, gsl_timestamp_t timestamp, unsigned int timeout)
{
gsl_device_t* device = &gsl_driver.device[device_id-1];
int status = GSL_FAILURE;
if (device->ftbl.device_waittimestamp)
{
status = device->ftbl.device_waittimestamp(device, timestamp, timeout);
}
return status;
}
//----------------------------------------------------------------------------
void
kgsl_cmdstream_memqueue_drain(gsl_device_t *device)
{
gsl_memnode_t *memnode, *nextnode, *freehead;
gsl_timestamp_t timestamp, ts_processed;
gsl_memqueue_t *memqueue = &device->memqueue;
// check head
if (memqueue->head == NULL)
{
return;
}
// get current EOP timestamp
ts_processed = kgsl_cmdstream_readtimestamp0(device->id, GSL_TIMESTAMP_RETIRED);
timestamp = memqueue->head->timestamp;
// check head timestamp
if (!(((ts_processed - timestamp) >= 0) || ((ts_processed - timestamp) < -GSL_TIMESTAMP_EPSILON)))
{
return;
}
memnode = memqueue->head;
freehead = memqueue->head;
// get node list to free
for(;;)
{
nextnode = memnode->next;
if (nextnode == NULL)
{
// entire queue drained
memqueue->head = NULL;
memqueue->tail = NULL;
break;
}
timestamp = nextnode->timestamp;
if (!(((ts_processed - timestamp) >= 0) || ((ts_processed - timestamp) < -GSL_TIMESTAMP_EPSILON)))
{
// drained up to a point
memqueue->head = nextnode;
memnode->next = NULL;
break;
}
memnode = nextnode;
}
// free nodes
while (freehead)
{
memnode = freehead;
freehead = memnode->next;
kgsl_sharedmem_free0(&memnode->memdesc, memnode->pid);
kfree(memnode);
}
}
//----------------------------------------------------------------------------
int
kgsl_cmdstream_freememontimestamp(gsl_deviceid_t device_id, gsl_memdesc_t *memdesc, gsl_timestamp_t timestamp, gsl_timestamp_type_t type)
{
gsl_memnode_t *memnode;
gsl_device_t *device = &gsl_driver.device[device_id-1];
gsl_memqueue_t *memqueue;
(void)type; // unref. For now just use EOP timestamp
mutex_lock(&gsl_driver.lock);
memqueue = &device->memqueue;
memnode = kmalloc(sizeof(gsl_memnode_t), GFP_KERNEL);
if (!memnode)
{
// other solution is to idle and free which given that the upper level driver probably wont check, probably a better idea
mutex_unlock(&gsl_driver.lock);
return (GSL_FAILURE);
}
memnode->timestamp = timestamp;
memnode->pid = current->tgid;
memnode->next = NULL;
memcpy(&memnode->memdesc, memdesc, sizeof(gsl_memdesc_t));
// add to end of queue
if (memqueue->tail != NULL)
{
memqueue->tail->next = memnode;
memqueue->tail = memnode;
}
else
{
DEBUG_ASSERT(memqueue->head == NULL);
memqueue->head = memnode;
memqueue->tail = memnode;
}
mutex_unlock(&gsl_driver.lock);
return (GSL_SUCCESS);
}
static int kgsl_cmdstream_timestamp_cmp(gsl_timestamp_t ts_new, gsl_timestamp_t ts_old)
{
gsl_timestamp_t ts_diff = ts_new - ts_old;
return (ts_diff >= 0) || (ts_diff < -GSL_TIMESTAMP_EPSILON);
}
int kgsl_cmdstream_check_timestamp(gsl_deviceid_t device_id, gsl_timestamp_t timestamp)
{
gsl_timestamp_t ts_processed;
ts_processed = kgsl_cmdstream_readtimestamp0(device_id, GSL_TIMESTAMP_RETIRED);
return kgsl_cmdstream_timestamp_cmp(ts_processed, timestamp);
}