mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-09-22 06:25:09 +00:00
Just to save work and get it up online. Current status;
GL not working as per usual
VG works - but closing Z160 device locks the driver (seems to be that
device_idle is called after the device is closed and there may be a
driver lock contention going on here).
imxng graphics driver works first run (same as above) but there are
some strange graphical glitches on smaller blits and rectangle fills,
which may be down to some kind of cache coherency problem.
Real (platform device) MMU enable causes the whole thing to explode,
since none of this got updated properly.
Tasks done:
* remove per-process support
* clean up use of device_id -> device since passing the id is a mess
for some reason 3D device isn't inited properly and some parts of
the driver call 3D device functions (notably on closing everything)
possibly because of some off-by-ones
* more global driver locking per qualcomm and to allow below fix
* clean up sharedmem and other APIs which used such semantics e.g.
kgsl_sharedmem_read -> lock, call kgsl_sharedmem_read0, unlock
to just use kgsl_sharedmem_read with manual locks before the call
where required, cleaning up the API a lot
* ditched the requirement for a device argument to sharedmem_alloc
since it never allocated from a per-device pool anyway. This is
a weird hack since the MMU setup needs a real device to set up
on.. Qualcomm's has a much better system and that will be in place
soon
* fixed the cmdstream_issueibcmds wrapper crap
* added kgsl_ringbuffer_issueibcmds to CMDSTREAM_ISSUEIBCMDS ioctl
again (no real effect)
* put kgsl_device_active in kgsl_g12_issueibcmds rather than calling
it manually before executing the function (ensures the autogating
is turned off before telling the Z160 to run a stream) from ioctl
* lots of ioctl debugging code (mostly commented out)
* function renames everywhere
* locks around suspend/resume
* removed a lot of the finegrained locking stuff as qualcomm doesn't
use it. That said, cmdwindow needs some locking (qcom uses a
spinlock) - will be added later
* LOTS of code cleanups/lint/checkpatch fixing
* removed interrupt handler abstraction
* Z160 idle timer update
* move more HAL stuff into the right places to remove the HAL more
* MMU handling cleanups (not complete, lots of it is disabled)
* NOTE: must re-add runpending to sharedmem_alloc? May not be required
when moving to new sharedmem API
* NOTE: check 3D interrupt enables
188 lines
5.2 KiB
C
188 lines
5.2 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 <linux/mxc_kgsl.h>
|
|
|
|
#include "kgsl_types.h"
|
|
#include "kgsl_mmu.h"
|
|
#include "kgsl_buildconfig.h"
|
|
#include "kgsl_device.h"
|
|
#include "kgsl_driver.h"
|
|
#include "kgsl_linux_map.h"
|
|
#include "kgsl_halconfig.h"
|
|
#include "kgsl_hal.h"
|
|
#include "kgsl_ringbuffer.h" // for defines for the include below!
|
|
#include "kgsl_cmdstream.h"
|
|
#include "kgsl_g12_vgv3types.h"
|
|
#include "kgsl_log.h"
|
|
|
|
|
|
// functions
|
|
|
|
int kgsl_cmdstream_init(struct kgsl_device *device)
|
|
{
|
|
return GSL_SUCCESS;
|
|
}
|
|
|
|
int kgsl_cmdstream_close(struct kgsl_device *device)
|
|
{
|
|
return GSL_SUCCESS;
|
|
}
|
|
|
|
unsigned int kgsl_cmdstream_readtimestamp(struct kgsl_device *device, enum kgsl_timestamp_type type)
|
|
{
|
|
unsigned int timestamp = 0;
|
|
|
|
KGSL_CMD_VDBG("enter (device_id=%d, type=%d)\n", device->id, type );
|
|
|
|
if (type == KGSL_TIMESTAMP_CONSUMED) {
|
|
// start-of-pipeline timestamp
|
|
KGSL_CMDSTREAM_GET_SOP_TIMESTAMP(device, ×tamp);
|
|
} else if (type == KGSL_TIMESTAMP_RETIRED) {
|
|
// end-of-pipeline timestamp
|
|
KGSL_CMDSTREAM_GET_EOP_TIMESTAMP(device, ×tamp);
|
|
}
|
|
|
|
KGSL_CMD_VDBG("return %d\n", timestamp);
|
|
|
|
return timestamp;
|
|
}
|
|
|
|
int kgsl_cmdstream_waittimestamp(struct kgsl_device *device, unsigned int timestamp, unsigned int timeout)
|
|
{
|
|
int status = GSL_FAILURE;
|
|
if (device->ftbl.waittimestamp) {
|
|
status = device->ftbl.waittimestamp(device, timestamp, timeout);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void kgsl_cmdstream_memqueue_drain(struct kgsl_device *device)
|
|
{
|
|
gsl_memnode_t *memnode, *nextnode, *freehead;
|
|
unsigned int timestamp, ts_processed;
|
|
gsl_memqueue_t *memqueue = &device->memqueue;
|
|
|
|
// check head
|
|
if (memqueue->head == NULL)
|
|
{
|
|
return;
|
|
}
|
|
// get current EOP timestamp
|
|
ts_processed = kgsl_cmdstream_readtimestamp(device, KGSL_TIMESTAMP_RETIRED);
|
|
timestamp = memqueue->head->timestamp;
|
|
// check head timestamp
|
|
if (!(((ts_processed - timestamp) >= 0) || ((ts_processed - timestamp) < -KGSL_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) < -KGSL_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_free(&memnode->memdesc);
|
|
kfree(memnode);
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
kgsl_cmdstream_freememontimestamp(struct kgsl_device *device, struct kgsl_memdesc *memdesc, unsigned int timestamp, enum kgsl_timestamp_type type)
|
|
{
|
|
gsl_memnode_t *memnode;
|
|
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->next = NULL;
|
|
memcpy(&memnode->memdesc, memdesc, sizeof(struct kgsl_memdesc));
|
|
|
|
// 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(unsigned int ts_new, unsigned int ts_old)
|
|
{
|
|
unsigned int ts_diff = ts_new - ts_old;
|
|
return (ts_diff >= 0) || (ts_diff < -KGSL_TIMESTAMP_EPSILON);
|
|
}
|
|
|
|
int kgsl_cmdstream_check_timestamp(struct kgsl_device *device, unsigned int timestamp)
|
|
{
|
|
unsigned int ts_processed;
|
|
ts_processed = kgsl_cmdstream_readtimestamp(device, KGSL_TIMESTAMP_RETIRED);
|
|
return kgsl_cmdstream_timestamp_cmp(ts_processed, timestamp);
|
|
}
|