msm: kgsl: Add per context timestamp

Add new ioctls for per context timestamps.
Timestamp functions (read/write/wait) will now be context
specific rather than only using the global timestamp.
Per context timestamps is a requirement for priority
based queueing.
This commit is contained in:
securecrt 2012-08-02 17:04:07 +08:00
parent 1e188cc5e1
commit 55ece772cd
13 changed files with 515 additions and 172 deletions

View File

@ -565,13 +565,13 @@ adreno_recover_hang(struct kgsl_device *device)
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
unsigned int timestamp;
unsigned int num_rb_contents;
unsigned int bad_context;
unsigned int reftimestamp;
unsigned int enable_ts;
unsigned int soptimestamp;
unsigned int eoptimestamp;
struct adreno_context *drawctxt;
unsigned int context_id;
struct kgsl_context *context;
struct adreno_context *adreno_context;
int next = 0;
KGSL_DRV_ERR(device, "Starting recovery from 3D GPU hang....\n");
@ -587,22 +587,35 @@ adreno_recover_hang(struct kgsl_device *device)
ret = adreno_ringbuffer_extract(rb, rb_buffer, &num_rb_contents);
if (ret)
goto done;
timestamp = rb->timestamp;
KGSL_DRV_ERR(device, "Last issued timestamp: %x\n", timestamp);
kgsl_sharedmem_readl(&device->memstore, &bad_context,
KGSL_DEVICE_MEMSTORE_OFFSET(current_context));
kgsl_sharedmem_readl(&device->memstore, &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
context = idr_find(&device->context_idr, context_id);
if (context == NULL) {
KGSL_DRV_ERR(device, "Last context unknown id:%d\n",
context_id);
context_id = KGSL_MEMSTORE_GLOBAL;
}
timestamp = rb->timestamp[KGSL_MEMSTORE_GLOBAL];
KGSL_DRV_ERR(device, "Last issued global timestamp: %x\n", timestamp);
kgsl_sharedmem_readl(&device->memstore, &reftimestamp,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts));
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts));
kgsl_sharedmem_readl(&device->memstore, &enable_ts,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable));
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable));
kgsl_sharedmem_readl(&device->memstore, &soptimestamp,
KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));
KGSL_MEMSTORE_OFFSET(context_id,
soptimestamp));
kgsl_sharedmem_readl(&device->memstore, &eoptimestamp,
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp));
KGSL_MEMSTORE_OFFSET(context_id,
eoptimestamp));
/* Make sure memory is synchronized before restarting the GPU */
mb();
KGSL_CTXT_ERR(device,
"Context that caused a GPU hang: %x\n", bad_context);
"Context id that caused a GPU hang: %d\n", context_id);
/* restart device */
ret = adreno_stop(device);
if (ret)
@ -613,20 +626,20 @@ adreno_recover_hang(struct kgsl_device *device)
KGSL_DRV_ERR(device, "Device has been restarted after hang\n");
/* Restore timestamp states */
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp),
KGSL_MEMSTORE_OFFSET(context_id, soptimestamp),
soptimestamp);
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp),
KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp),
eoptimestamp);
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp),
KGSL_MEMSTORE_OFFSET(context_id, soptimestamp),
soptimestamp);
if (num_rb_contents) {
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
KGSL_MEMSTORE_OFFSET(context_id, ref_wait_ts),
reftimestamp);
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable),
KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable),
enable_ts);
}
/* Make sure all writes are posted before the GPU reads them */
@ -634,12 +647,12 @@ adreno_recover_hang(struct kgsl_device *device)
/* Mark the invalid context so no more commands are accepted from
* that context */
drawctxt = (struct adreno_context *) bad_context;
adreno_context = context->devctxt;
KGSL_CTXT_ERR(device,
"Context that caused a GPU hang: %x\n", bad_context);
"Context that caused a GPU hang: %d\n", adreno_context->id);
drawctxt->flags |= CTXT_FLAGS_GPU_HANG;
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
/*
* Set the reset status of all contexts to
@ -649,7 +662,7 @@ adreno_recover_hang(struct kgsl_device *device)
while ((context = idr_get_next(&device->context_idr, &next))) {
if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
context->reset_status) {
if (context->devctxt != drawctxt)
if (context->id != context_id)
context->reset_status =
KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
else
@ -661,7 +674,7 @@ adreno_recover_hang(struct kgsl_device *device)
/* Restore valid commands in ringbuffer */
adreno_ringbuffer_restore(rb, rb_buffer, num_rb_contents);
rb->timestamp = timestamp;
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
done:
vfree(rb_buffer);
return ret;
@ -755,7 +768,8 @@ static int adreno_getproperty(struct kgsl_device *device,
shadowprop.size = device->memstore.size;
/* GSL needs this to be set, even if it
appears to be meaningless */
shadowprop.flags = KGSL_FLAGS_INITIALIZED;
shadowprop.flags = KGSL_FLAGS_INITIALIZED |
KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS;
}
if (copy_to_user(value, &shadowprop,
sizeof(shadowprop))) {
@ -1011,38 +1025,58 @@ void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
__raw_writel(value, reg);
}
static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
{
unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
if (k_ctxt != NULL) {
struct adreno_context *a_ctxt = k_ctxt->devctxt;
/*
* if the context was not created with per context timestamp
* support, we must use the global timestamp since issueibcmds
* will be returning that one.
*/
if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = a_ctxt->id;
}
return context_id;
}
static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
unsigned int timestamp)
struct kgsl_context *context, unsigned int timestamp)
{
int status;
unsigned int ref_ts, enableflag;
unsigned int context_id = _get_context_id(context);
status = kgsl_check_timestamp(device, timestamp);
status = kgsl_check_timestamp(device, context, timestamp);
if (!status) {
mutex_lock(&device->mutex);
kgsl_sharedmem_readl(&device->memstore, &enableflag,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable));
KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
mb();
if (enableflag) {
kgsl_sharedmem_readl(&device->memstore, &ref_ts,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts));
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts));
mb();
if (timestamp_cmp(ref_ts, timestamp) >= 0) {
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
timestamp);
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
wmb();
}
} else {
unsigned int cmds[2];
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
timestamp);
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
enableflag = 1;
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable),
enableflag);
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), enableflag);
wmb();
/* submit a dummy packet so that even if all
* commands upto timestamp get executed we will still
@ -1076,6 +1110,7 @@ static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
/* MUST be called with the device mutex held */
static int adreno_waittimestamp(struct kgsl_device *device,
struct kgsl_context *context,
unsigned int timestamp,
unsigned int msecs)
{
@ -1087,15 +1122,19 @@ static int adreno_waittimestamp(struct kgsl_device *device,
int retries;
unsigned int msecs_first;
unsigned int msecs_part;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
/* Don't wait forever, set a max value for now */
if (msecs == -1)
msecs = adreno_dev->wait_timeout;
if (timestamp_cmp(timestamp, adreno_dev->ringbuffer.timestamp) > 0) {
KGSL_DRV_ERR(device, "Cannot wait for invalid ts: %x, "
"rb->timestamp: %x\n",
timestamp, adreno_dev->ringbuffer.timestamp);
if (timestamp_cmp(timestamp, ts_issued) > 0) {
KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, "
"last issued ts <%d:0x%x>\n",
context_id, timestamp, context_id, ts_issued);
status = -EINVAL;
goto done;
}
@ -1107,7 +1146,7 @@ static int adreno_waittimestamp(struct kgsl_device *device,
msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
msecs_part = (msecs - msecs_first + 3) / 4;
for (retries = 0; retries < 5; retries++) {
if (kgsl_check_timestamp(device, timestamp)) {
if (kgsl_check_timestamp(device, context, timestamp)) {
/* if the timestamp happens while we're not
* waiting, there's a chance that an interrupt
* will not be generated and thus the timestamp
@ -1130,7 +1169,7 @@ static int adreno_waittimestamp(struct kgsl_device *device,
status = kgsl_wait_event_interruptible_timeout(
device->wait_queue,
kgsl_check_interrupt_timestamp(device,
timestamp),
context, timestamp),
msecs_to_jiffies(retries ?
msecs_part : msecs_first), io);
mutex_lock(&device->mutex);
@ -1147,9 +1186,10 @@ static int adreno_waittimestamp(struct kgsl_device *device,
}
status = -ETIMEDOUT;
KGSL_DRV_ERR(device,
"Device hang detected while waiting for timestamp: %x,"
"last submitted(rb->timestamp): %x, wptr: %x\n",
timestamp, adreno_dev->ringbuffer.timestamp,
"Device hang detected while waiting for timestamp: "
"<%d:0x%x>, last submitted timestamp: <%d:0x%x>, "
"wptr: 0x%x\n",
context_id, timestamp, context_id, ts_issued,
adreno_dev->ringbuffer.wptr);
if (!adreno_dump_and_recover(device)) {
/* wait for idle after recovery as the
@ -1163,15 +1203,17 @@ done:
}
static unsigned int adreno_readtimestamp(struct kgsl_device *device,
enum kgsl_timestamp_type type)
struct kgsl_context *context, enum kgsl_timestamp_type type)
{
unsigned int timestamp = 0;
unsigned int context_id = _get_context_id(context);
if (type == KGSL_TIMESTAMP_CONSUMED)
adreno_regread(device, REG_CP_TIMESTAMP, &timestamp);
else if (type == KGSL_TIMESTAMP_RETIRED)
kgsl_sharedmem_readl(&device->memstore, &timestamp,
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp));
KGSL_MEMSTORE_OFFSET(context_id,
eoptimestamp));
rmb();
return timestamp;

View File

@ -1427,8 +1427,8 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
cmds[3] = device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
cmds[4] = (unsigned int) context;
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->id;
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
kgsl_mmu_setstate(device, context->pagetable);
@ -1551,11 +1551,18 @@ static void a2xx_cp_intrcallback(struct kgsl_device *device)
if (status & CP_INT_CNTL__RB_INT_MASK) {
/* signal intr completion event */
unsigned int enableflag = 0;
unsigned int context_id;
kgsl_sharedmem_readl(&device->memstore,
&context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
if (context_id < KGSL_MEMSTORE_MAX) {
kgsl_sharedmem_writel(&rb->device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable),
enableflag);
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), 0);
device->last_expired_ctxt_id = context_id;
wmb();
}
KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
}
@ -1780,7 +1787,6 @@ static void a2xx_gmeminit(struct adreno_device *adreno_dev)
static void a2xx_start(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = &adreno_dev->dev;
int init_reftimestamp = 0x7fffffff;
/*
* We need to make sure all blocks are powered up and clocked
@ -1833,12 +1839,6 @@ static void a2xx_start(struct adreno_device *adreno_dev)
else
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0x80);
kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size);
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts),
init_reftimestamp);
adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000);
/* Make sure interrupts are disabled */

View File

@ -2222,8 +2222,8 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
cmds[3] = device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
cmds[4] = (unsigned int)context;
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->id;
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
kgsl_mmu_setstate(device, context->pagetable);
@ -2366,9 +2366,17 @@ static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
if (irq == A3XX_INT_CP_RB_INT) {
unsigned int context_id;
kgsl_sharedmem_readl(&adreno_dev->dev.memstore,
&context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
if (context_id < KGSL_MEMSTORE_MAX) {
kgsl_sharedmem_writel(&rb->device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable), 0);
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), 0);
wmb();
}
KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2002,2007-2012, 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
@ -17,6 +17,8 @@
#include "kgsl_sharedmem.h"
#include "adreno.h"
#define KGSL_INIT_REFTIMESTAMP 0x7FFFFFFF
/* quad for copying GMEM to context shadow */
#define QUAD_LEN 12
#define QUAD_RESTORE_LEN 14
@ -154,6 +156,7 @@ int adreno_drawctxt_create(struct kgsl_device *device,
drawctxt->pagetable = pagetable;
drawctxt->bin_base_offset = 0;
drawctxt->id = context->id;
if (flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
@ -161,10 +164,17 @@ int adreno_drawctxt_create(struct kgsl_device *device,
if (flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
if (flags & KGSL_CONTEXT_PER_CONTEXT_TS)
drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
context->devctxt = drawctxt;
return 0;
err:

View File

@ -40,6 +40,10 @@
#define CTXT_FLAGS_GPU_HANG 0x00008000
/* Specifies there is no need to save GMEM */
#define CTXT_FLAGS_NOGMEMALLOC 0x00010000
/* Trash state for context */
#define CTXT_FLAGS_TRASHSTATE 0x00020000
/* per context timestamps enabled */
#define CTXT_FLAGS_PER_CONTEXT_TS 0x00040000
struct kgsl_device;
struct adreno_device;
@ -72,6 +76,7 @@ struct gmem_shadow_t {
};
struct adreno_context {
unsigned int id;
uint32_t flags;
struct kgsl_pagetable *pagetable;
struct kgsl_memdesc gpustate;

View File

@ -14,6 +14,7 @@
#include <linux/vmalloc.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
#include "adreno.h"
#include "adreno_pm4types.h"
@ -464,7 +465,9 @@ static int adreno_dump(struct kgsl_device *device)
const uint32_t *rb_vaddr;
int num_item = 0;
int read_idx, write_idx;
unsigned int ts_processed;
unsigned int ts_processed = 0xdeaddead;
struct kgsl_context *context;
unsigned int context_id;
static struct ib_list ib_list;
@ -660,9 +663,18 @@ static int adreno_dump(struct kgsl_device *device)
KGSL_LOG_DUMP(device,
"MH_INTERRUPT: MASK = %08X | STATUS = %08X\n", r1, r2);
ts_processed = device->ftbl->readtimestamp(device,
kgsl_sharedmem_readl(&device->memstore,
(unsigned int *) &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
context = idr_find(&device->context_idr, context_id);
if (context) {
ts_processed = device->ftbl->readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
KGSL_LOG_DUMP(device, "TIMESTM RTRD: %08X\n", ts_processed);
KGSL_LOG_DUMP(device, "CTXT: %d TIMESTM RTRD: %08X\n",
context->id, ts_processed);
} else
KGSL_LOG_DUMP(device, "BAD CTXT: %d\n", context_id);
num_item = adreno_ringbuffer_count(&adreno_dev->ringbuffer,
cp_rb_rptr);

View File

@ -236,7 +236,7 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
return 0;
if (init_ram) {
rb->timestamp = 0;
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
GSL_RB_INIT_TIMESTAMP(rb);
}
@ -321,18 +321,13 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
}
/* setup scratch/timestamp */
adreno_regwrite(device, REG_SCRATCH_ADDR,
device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));
adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
soptimestamp));
adreno_regwrite(device, REG_SCRATCH_UMSK,
GSL_RB_MEMPTRS_SCRATCH_MASK);
/* update the eoptimestamp field with the last retired timestamp */
kgsl_sharedmem_writel(&device->memstore,
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp),
rb->timestamp);
/* load the CP ucode */
status = adreno_ringbuffer_load_pm4_ucode(device);
@ -431,15 +426,28 @@ void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
static uint32_t
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
struct adreno_context *context,
unsigned int flags, unsigned int *cmds,
int sizedwords)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
unsigned int *ringcmds;
unsigned int timestamp;
unsigned int total_sizedwords = sizedwords + 6;
unsigned int total_sizedwords = sizedwords;
unsigned int i;
unsigned int rcmd_gpu;
unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
unsigned int gpuaddr = rb->device->memstore.gpuaddr;
if (context != NULL) {
/*
* if the context was not created with per context timestamp
* support, we must use the global timestamp since issueibcmds
* will be returning that one.
*/
if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = context->id;
}
/* reserve space to temporarily turn off protected mode
* error checking if needed
@ -451,6 +459,13 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
total_sizedwords += 2; /* scratchpad ts for recovery */
if (context) {
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
}
total_sizedwords += 4; /* global timestamp for recovery*/
ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
@ -478,12 +493,20 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
}
rb->timestamp++;
timestamp = rb->timestamp;
/* always increment the global timestamp. once. */
rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
if (context) {
if (context_id == KGSL_MEMSTORE_GLOBAL)
rb->timestamp[context_id] =
rb->timestamp[KGSL_MEMSTORE_GLOBAL];
else
rb->timestamp[context_id]++;
}
timestamp = rb->timestamp[context_id];
/* start-of-pipeline and end-of-pipeline timestamps */
/* scratchpad ts for recovery */
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
if (adreno_is_a3xx(adreno_dev)) {
/*
@ -499,22 +522,41 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
}
if (context) {
/* start-of-pipeline timestamp */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
/* end-of-pipeline timestamp */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
}
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu,
(rb->device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp)));
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
/* Conditional execution based on memory values */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable)) >> 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts)) >> 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ts_cmp_enable)) >> 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ref_wait_ts)) >> 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
/* # of conditional command DWORDs */
GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu,
@ -533,7 +575,6 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
adreno_ringbuffer_submit(rb);
/* return timestamp of issued coREG_ands */
return timestamp;
}
@ -548,7 +589,7 @@ adreno_ringbuffer_issuecmds(struct kgsl_device *device,
if (device->state & KGSL_STATE_HUNG)
return;
adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
adreno_ringbuffer_addcmds(rb, NULL, flags, cmds, sizedwords);
}
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@ -769,8 +810,8 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
" will not accept commands for this context\n",
drawctxt);
" will not accept commands for context %d\n",
drawctxt, drawctxt->id);
return -EDEADLK;
}
@ -822,6 +863,7 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
*timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
KGSL_CMD_FLAGS_NOT_KERNEL_CMD,
&link[0], (cmds - link));
@ -855,11 +897,25 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
unsigned int val2;
unsigned int val3;
unsigned int copy_rb_contents = 0;
unsigned int cur_context;
struct kgsl_context *context;
unsigned int context_id;
GSL_RB_GET_READPTR(rb, &rb->rptr);
retired_timestamp = device->ftbl->readtimestamp(device,
/* current_context is the context that is presently active in the
* GPU, i.e the context in which the hang is caused */
kgsl_sharedmem_readl(&device->memstore, &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
KGSL_DRV_ERR(device, "Last context id: %d\n", context_id);
context = idr_find(&device->context_idr, context_id);
if (context == NULL) {
KGSL_DRV_ERR(device,
"GPU recovery from hang not possible because last"
" context id is invalid.\n");
return -EINVAL;
}
retired_timestamp = device->ftbl->readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
retired_timestamp);
@ -894,7 +950,8 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
(val1 == cp_type3_packet(CP_EVENT_WRITE, 3)
&& val2 == CACHE_FLUSH_TS &&
val3 == (rb->device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)))) {
KGSL_MEMSTORE_OFFSET(context_id,
eoptimestamp)))) {
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
KGSL_DRV_ERR(device,
@ -940,10 +997,6 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
return -EINVAL;
}
/* current_context is the context that is presently active in the
* GPU, i.e the context in which the hang is caused */
kgsl_sharedmem_readl(&device->memstore, &cur_context,
KGSL_DEVICE_MEMSTORE_OFFSET(current_context));
while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
@ -958,7 +1011,8 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
BUG_ON(val1 != (device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(current_context)));
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context)));
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
@ -970,7 +1024,7 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
* and leave.
*/
if ((copy_rb_contents == 0) && (value == cur_context)) {
if ((copy_rb_contents == 0) && (value == context_id)) {
KGSL_DRV_ERR(device, "GPU recovery could not "
"find the previous context\n");
return -EINVAL;
@ -986,7 +1040,7 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
/* if context switches to a context that did not cause
* hang then start saving the rb contents as those
* commands can be executed */
if (value != cur_context) {
if (value != context_id) {
copy_rb_contents = 1;
temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
temp_rb_buffer[temp_idx++] =

View File

@ -54,7 +54,8 @@ struct adreno_ringbuffer {
unsigned int wptr; /* write pointer offset in dwords from baseaddr */
unsigned int rptr; /* read pointer offset in dwords from baseaddr */
uint32_t timestamp;
unsigned int timestamp[KGSL_MEMSTORE_MAX];
};

View File

@ -58,22 +58,30 @@ static struct ion_client *kgsl_ion_client;
* @returns - 0 on success or error code on failure
*/
static int kgsl_add_event(struct kgsl_device *device, u32 ts,
void (*cb)(struct kgsl_device *, void *, u32), void *priv,
static int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
struct kgsl_device_private *owner)
{
struct kgsl_event *event;
struct list_head *n;
unsigned int cur = device->ftbl->readtimestamp(device,
KGSL_TIMESTAMP_RETIRED);
unsigned int cur_ts;
struct kgsl_context *context = NULL;
if (cb == NULL)
return -EINVAL;
if (id != KGSL_MEMSTORE_GLOBAL) {
context = idr_find(&device->context_idr, id);
if (context == NULL)
return -EINVAL;
}
cur_ts = device->ftbl->readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
/* Check to see if the requested timestamp has already fired */
if (timestamp_cmp(cur, ts) >= 0) {
cb(device, priv, cur);
if (timestamp_cmp(cur_ts, ts) >= 0) {
cb(device, priv, id, cur_ts);
return 0;
}
@ -81,17 +89,24 @@ static int kgsl_add_event(struct kgsl_device *device, u32 ts,
if (event == NULL)
return -ENOMEM;
event->context = context;
event->timestamp = ts;
event->priv = priv;
event->func = cb;
event->owner = owner;
/* Add the event in order to the list */
/*
* Add the event in order to the list. Order is by context id
* first and then by timestamp for that context.
*/
for (n = device->events.next ; n != &device->events; n = n->next) {
struct kgsl_event *e =
list_entry(n, struct kgsl_event, list);
if (e->context != context)
continue;
if (timestamp_cmp(e->timestamp, ts) > 0) {
list_add(&event->list, n->prev);
break;
@ -115,12 +130,16 @@ static void kgsl_cancel_events(struct kgsl_device *device,
struct kgsl_device_private *owner)
{
struct kgsl_event *event, *event_tmp;
unsigned int cur = device->ftbl->readtimestamp(device,
KGSL_TIMESTAMP_RETIRED);
unsigned int id, cur;
list_for_each_entry_safe(event, event_tmp, &device->events, list) {
if (event->owner != owner)
continue;
cur = device->ftbl->readtimestamp(device, event->context,
KGSL_TIMESTAMP_RETIRED);
id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
/*
* "cancel" the events by calling their callback.
* Currently, events are used for lock and memory
@ -128,7 +147,7 @@ static void kgsl_cancel_events(struct kgsl_device *device,
* thing to do is release or free.
*/
if (event->func)
event->func(device, event->priv, cur);
event->func(device, event->priv, id, cur);
list_del(&event->list);
kfree(event);
@ -265,8 +284,8 @@ kgsl_create_context(struct kgsl_device_private *dev_priv)
return NULL;
}
ret = idr_get_new(&dev_priv->device->context_idr,
context, &id);
ret = idr_get_new_above(&dev_priv->device->context_idr,
context, 1, &id);
if (ret != -EAGAIN)
break;
@ -277,6 +296,16 @@ kgsl_create_context(struct kgsl_device_private *dev_priv)
return NULL;
}
/* MAX - 1, there is one memdesc in memstore for device info */
if (id >= KGSL_MEMSTORE_MAX) {
KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d "
"ctxts due to memstore limitation\n",
KGSL_MEMSTORE_MAX);
idr_remove(&dev_priv->device->context_idr, id);
kfree(context);
return NULL;
}
context->id = id;
context->dev_priv = dev_priv;
@ -307,25 +336,28 @@ static void kgsl_timestamp_expired(struct work_struct *work)
ts_expired_ws);
struct kgsl_event *event, *event_tmp;
uint32_t ts_processed;
unsigned int id;
mutex_lock(&device->mutex);
/* get current EOP timestamp */
ts_processed = device->ftbl->readtimestamp(device,
KGSL_TIMESTAMP_RETIRED);
/* Process expired events */
list_for_each_entry_safe(event, event_tmp, &device->events, list) {
ts_processed = device->ftbl->readtimestamp(device,
event->context, KGSL_TIMESTAMP_RETIRED);
if (timestamp_cmp(ts_processed, event->timestamp) < 0)
break;
continue;
id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
if (event->func)
event->func(device, event->priv, ts_processed);
event->func(device, event->priv, id, ts_processed);
list_del(&event->list);
kfree(event);
}
device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
mutex_unlock(&device->mutex);
}
@ -400,11 +432,15 @@ int kgsl_unregister_ts_notifier(struct kgsl_device *device,
}
EXPORT_SYMBOL(kgsl_unregister_ts_notifier);
int kgsl_check_timestamp(struct kgsl_device *device, unsigned int timestamp)
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
unsigned int ts_processed;
unsigned int global;
ts_processed = device->ftbl->readtimestamp(device,
ts_processed = device->ftbl->readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
global = device->ftbl->readtimestamp(device, NULL,
KGSL_TIMESTAMP_RETIRED);
return (timestamp_cmp(ts_processed, timestamp) >= 0);
@ -745,6 +781,9 @@ static int kgsl_open(struct inode *inodep, struct file *filep)
kgsl_check_suspended(device);
if (device->open_count == 0) {
kgsl_sharedmem_set(&device->memstore, 0, 0,
device->memstore.size);
result = device->ftbl->start(device, true);
if (result) {
@ -885,21 +924,35 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
return result;
}
static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
int result = 0;
struct kgsl_device_waittimestamp *param = data;
/* The getproperty struct is reused for setproperty too */
struct kgsl_device_getproperty *param = data;
/* Set the active count so that suspend doesn't do the
wrong thing */
if (dev_priv->device->ftbl->setproperty)
result = dev_priv->device->ftbl->setproperty(
dev_priv->device, param->type,
param->value, param->sizebytes);
return result;
}
static long _device_waittimestamp(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
unsigned int timestamp,
unsigned int timeout)
{
int result = 0;
/* Set the active count so that suspend doesn't do the wrong thing */
dev_priv->device->active_cnt++;
result = dev_priv->device->ftbl->waittimestamp(dev_priv->device,
param->timestamp,
param->timeout);
context, timestamp, timeout);
/* Fire off any pending suspend operations that are in flight */
@ -910,6 +963,34 @@ static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
return result;
}
static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_device_waittimestamp *param = data;
return _device_waittimestamp(dev_priv, KGSL_MEMSTORE_GLOBAL,
param->timestamp, param->timeout);
}
static long kgsl_ioctl_device_waittimestamp_ctxtid(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_device_waittimestamp_ctxtid *param = data;
struct kgsl_context *context;
context = kgsl_find_context(dev_priv, param->context_id);
if (context == NULL) {
KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
param->context_id);
return -EINVAL;
}
return _device_waittimestamp(dev_priv, context,
param->timestamp, param->timeout);
}
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@ -926,7 +1007,7 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
if (context == NULL) {
result = -EINVAL;
KGSL_DRV_ERR(dev_priv->device,
"invalid drawctxt drawctxt_id %d\n",
"invalid context_id %d\n",
param->drawctxt_id);
goto done;
}
@ -997,21 +1078,46 @@ done:
return result;
}
static long _cmdstream_readtimestamp(struct kgsl_device_private *dev_priv,
struct kgsl_context *context, unsigned int type,
unsigned int *timestamp)
{
*timestamp = dev_priv->device->ftbl->readtimestamp(dev_priv->device,
context, type);
return 0;
}
static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_cmdstream_readtimestamp *param = data;
param->timestamp =
dev_priv->device->ftbl->readtimestamp(dev_priv->device,
param->type);
return _cmdstream_readtimestamp(dev_priv, NULL,
param->type, &param->timestamp);
}
return 0;
static long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_cmdstream_readtimestamp_ctxtid *param = data;
struct kgsl_context *context;
context = kgsl_find_context(dev_priv, param->context_id);
if (context == NULL) {
KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
param->context_id);
return -EINVAL;
}
return _cmdstream_readtimestamp(dev_priv, context,
param->type, &param->timestamp);
}
static void kgsl_freemem_event_cb(struct kgsl_device *device,
void *priv, u32 timestamp)
void *priv, u32 id, u32 timestamp)
{
struct kgsl_mem_entry *entry = priv;
spin_lock(&entry->priv->mem_lock);
@ -1020,30 +1126,65 @@ static void kgsl_freemem_event_cb(struct kgsl_device *device,
kgsl_mem_entry_detach_process(entry);
}
static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv,
unsigned int gpuaddr, struct kgsl_context *context,
unsigned int timestamp, unsigned int type)
{
int result = 0;
struct kgsl_cmdstream_freememontimestamp *param = data;
struct kgsl_mem_entry *entry = NULL;
struct kgsl_device *device = dev_priv->device;
unsigned int cur;
unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
spin_lock(&dev_priv->process_priv->mem_lock);
entry = kgsl_sharedmem_find(dev_priv->process_priv, param->gpuaddr);
entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
spin_unlock(&dev_priv->process_priv->mem_lock);
if (entry) {
result = kgsl_add_event(dev_priv->device, param->timestamp,
kgsl_freemem_event_cb, entry, dev_priv);
cur = device->ftbl->readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
result = kgsl_add_event(dev_priv->device, context_id,
timestamp, kgsl_freemem_event_cb,
entry, dev_priv);
} else {
KGSL_DRV_ERR(dev_priv->device,
"invalid gpuaddr %08x\n", param->gpuaddr);
"invalid gpuaddr %08x\n", gpuaddr);
result = -EINVAL;
}
return result;
}
static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_cmdstream_freememontimestamp *param = data;
return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
NULL, param->timestamp, param->type);
}
static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(
struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
{
struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data;
struct kgsl_context *context;
context = kgsl_find_context(dev_priv, param->context_id);
if (context == NULL) {
KGSL_DRV_ERR(dev_priv->device,
"invalid drawctxt context_id %d\n", param->context_id);
return -EINVAL;
}
return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
context, param->timestamp, param->type);
}
static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@ -1760,13 +1901,14 @@ struct kgsl_genlock_event_priv {
* kgsl_genlock_event_cb - Event callback for a genlock timestamp event
* @device - The KGSL device that expired the timestamp
* @priv - private data for the event
* @context_id - the context id that goes with the timestamp
* @timestamp - the timestamp that triggered the event
*
* Release a genlock lock following the expiration of a timestamp
*/
static void kgsl_genlock_event_cb(struct kgsl_device *device,
void *priv, u32 timestamp)
void *priv, u32 context_id, u32 timestamp)
{
struct kgsl_genlock_event_priv *ev = priv;
int ret;
@ -1794,7 +1936,7 @@ static void kgsl_genlock_event_cb(struct kgsl_device *device,
*/
static int kgsl_add_genlock_event(struct kgsl_device *device,
u32 timestamp, void __user *data, int len,
u32 context_id, u32 timestamp, void __user *data, int len,
struct kgsl_device_private *owner)
{
struct kgsl_genlock_event_priv *event;
@ -1820,8 +1962,8 @@ static int kgsl_add_genlock_event(struct kgsl_device *device,
return ret;
}
ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event,
owner);
ret = kgsl_add_event(device, context_id, timestamp,
kgsl_genlock_event_cb, event, owner);
if (ret)
kfree(event);
@ -1829,7 +1971,7 @@ static int kgsl_add_genlock_event(struct kgsl_device *device,
}
#else
static long kgsl_add_genlock_event(struct kgsl_device *device,
u32 timestamp, void __user *data, int len,
u32 context_id, u32 timestamp, void __user *data, int len,
struct kgsl_device_private *owner)
{
return -EINVAL;
@ -1853,8 +1995,8 @@ static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
switch (param->type) {
case KGSL_TIMESTAMP_EVENT_GENLOCK:
ret = kgsl_add_genlock_event(dev_priv->device,
param->timestamp, param->priv, param->len,
dev_priv);
param->context_id, param->timestamp, param->priv,
param->len, dev_priv);
break;
default:
ret = -EINVAL;
@ -1878,12 +2020,18 @@ static const struct {
kgsl_ioctl_device_getproperty, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
kgsl_ioctl_device_waittimestamp, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
kgsl_ioctl_device_waittimestamp_ctxtid, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
kgsl_ioctl_rb_issueibcmds, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
kgsl_ioctl_cmdstream_readtimestamp, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
kgsl_ioctl_cmdstream_readtimestamp_ctxtid, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
kgsl_ioctl_cmdstream_freememontimestamp, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
kgsl_ioctl_cmdstream_freememontimestamp_ctxtid, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
kgsl_ioctl_drawctxt_create, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
@ -1906,6 +2054,8 @@ static const struct {
kgsl_ioctl_cff_user_event, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
kgsl_ioctl_timestamp_event, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
kgsl_ioctl_device_setproperty, 1),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@ -2211,13 +2361,13 @@ kgsl_register_device(struct kgsl_device *device)
INIT_LIST_HEAD(&device->events);
device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
ret = kgsl_mmu_init(device);
if (ret != 0)
goto err_dest_work_q;
ret = kgsl_allocate_contiguous(&device->memstore,
sizeof(struct kgsl_devmemstore));
ret = kgsl_allocate_contiguous(&device->memstore, KGSL_MEMSTORE_SIZE);
if (ret != 0)
goto err_close_mmu;

View File

@ -25,6 +25,14 @@
#define KGSL_NAME "kgsl"
/* The number of memstore arrays limits the number of contexts allowed.
* If more contexts are needed, update multiple for MEMSTORE_SIZE
*/
#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 2))
#define KGSL_MEMSTORE_GLOBAL (0)
#define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \
sizeof(struct kgsl_devmemstore) - 1)
/* Timestamp window used to detect rollovers */
#define KGSL_TIMESTAMP_WINDOW 0x80000000
@ -150,6 +158,7 @@ struct kgsl_mem_entry {
void *priv_data;
struct list_head list;
uint32_t free_timestamp;
unsigned int context_id;
/* back pointer to private structure under whose context this
* allocation is made */
struct kgsl_process_private *priv;

View File

@ -1,5 +1,4 @@
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
* Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
/* Copyright (c) 2002,2007-2012, 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
@ -47,6 +46,7 @@
#define KGSL_STATE_SUSPEND 0x00000010
#define KGSL_STATE_HUNG 0x00000020
#define KGSL_STATE_DUMP_AND_RECOVER 0x00000040
#define KGSL_STATE_SLUMBER 0x00000080
#define KGSL_GRAPHICS_MEMORY_LOW_WATERMARK 0x1000000
@ -76,9 +76,10 @@ struct kgsl_functable {
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*waittimestamp) (struct kgsl_device *device,
unsigned int timestamp, unsigned int msecs);
struct kgsl_context *context, unsigned int timestamp,
unsigned int msecs);
unsigned int (*readtimestamp) (struct kgsl_device *device,
enum kgsl_timestamp_type type);
struct kgsl_context *context, enum kgsl_timestamp_type type);
int (*issueibcmds) (struct kgsl_device_private *dev_priv,
struct kgsl_context *context, struct kgsl_ibdesc *ibdesc,
unsigned int sizedwords, uint32_t *timestamp,
@ -101,6 +102,9 @@ struct kgsl_functable {
struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
int (*setproperty) (struct kgsl_device *device,
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
};
struct kgsl_memregion {
@ -120,8 +124,9 @@ struct kgsl_mh {
};
struct kgsl_event {
struct kgsl_context *context;
uint32_t timestamp;
void (*func)(struct kgsl_device *, void *, u32);
void (*func)(struct kgsl_device *, void *, u32, u32);
void *priv;
struct list_head list;
struct kgsl_device_private *owner;
@ -153,6 +158,7 @@ struct kgsl_device {
uint32_t state;
uint32_t requested_state;
unsigned int last_expired_ctxt_id;
unsigned int active_cnt;
struct completion suspend_gate;
@ -304,7 +310,8 @@ kgsl_find_context(struct kgsl_device_private *dev_priv, uint32_t id)
return (ctxt && ctxt->dev_priv == dev_priv) ? ctxt : NULL;
}
int kgsl_check_timestamp(struct kgsl_device *device, unsigned int timestamp);
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp);
int kgsl_register_ts_notifier(struct kgsl_device *device,
struct notifier_block *nb);

14
drivers/gpu/msm/z180.c Normal file → Executable file
View File

@ -100,6 +100,7 @@ enum z180_cmdwindow_type {
static int z180_start(struct kgsl_device *device, unsigned int init_ram);
static int z180_stop(struct kgsl_device *device);
static int z180_wait(struct kgsl_device *device,
struct kgsl_context *context,
unsigned int timestamp,
unsigned int msecs);
static void z180_regread(struct kgsl_device *device,
@ -382,8 +383,8 @@ static int z180_idle(struct kgsl_device *device, unsigned int timeout)
if (timestamp_cmp(z180_dev->current_timestamp,
z180_dev->timestamp) > 0)
status = z180_wait(device, z180_dev->current_timestamp,
timeout);
status = z180_wait(device, NULL,
z180_dev->current_timestamp, timeout);
if (status)
KGSL_DRV_ERR(device, "z180_waittimestamp() timed out\n");
@ -793,14 +794,16 @@ static void z180_cmdwindow_write(struct kgsl_device *device,
}
static unsigned int z180_readtimestamp(struct kgsl_device *device,
enum kgsl_timestamp_type type)
struct kgsl_context *context, enum kgsl_timestamp_type type)
{
struct z180_device *z180_dev = Z180_DEVICE(device);
(void)context;
/* get current EOP timestamp */
return z180_dev->timestamp;
}
static int z180_waittimestamp(struct kgsl_device *device,
struct kgsl_context *context,
unsigned int timestamp,
unsigned int msecs)
{
@ -811,13 +814,14 @@ static int z180_waittimestamp(struct kgsl_device *device,
msecs = 10 * MSEC_PER_SEC;
mutex_unlock(&device->mutex);
status = z180_wait(device, timestamp, msecs);
status = z180_wait(device, context, timestamp, msecs);
mutex_lock(&device->mutex);
return status;
}
static int z180_wait(struct kgsl_device *device,
struct kgsl_context *context,
unsigned int timestamp,
unsigned int msecs)
{
@ -826,7 +830,7 @@ static int z180_wait(struct kgsl_device *device,
timeout = wait_io_event_interruptible_timeout(
device->wait_queue,
kgsl_check_timestamp(device, timestamp),
kgsl_check_timestamp(device, context, timestamp),
msecs_to_jiffies(msecs));
if (timeout > 0)

View File

@ -35,14 +35,18 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
#define KGSL_VERSION_MINOR 8
#define KGSL_VERSION_MINOR 10
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 1
#define KGSL_CONTEXT_NO_GMEM_ALLOC 2
#define KGSL_CONTEXT_SUBMIT_IB_LIST 4
#define KGSL_CONTEXT_CTX_SWITCH 8
#define KGSL_CONTEXT_PREAMBLE 16
#define KGSL_CONTEXT_SAVE_GMEM 0x00000001
#define KGSL_CONTEXT_NO_GMEM_ALLOC 0x00000002
#define KGSL_CONTEXT_SUBMIT_IB_LIST 0x00000004
#define KGSL_CONTEXT_CTX_SWITCH 0x00000008
#define KGSL_CONTEXT_PREAMBLE 0x00000010
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
#define KGSL_CONTEXT_INVALID 0xffffffff
/* Memory allocayion flags */
#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
@ -58,6 +62,7 @@
#define KGSL_FLAGS_RESERVED1 0x00000040
#define KGSL_FLAGS_RESERVED2 0x00000080
#define KGSL_FLAGS_SOFT_RESET 0x00000100
#define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200
/* Clock flags to show which clocks should be controled by a given platform */
#define KGSL_CLK_SRC 0x00000001
@ -132,9 +137,9 @@ struct kgsl_devmemstore {
unsigned int sbz5;
};
#define KGSL_DEVICE_MEMSTORE_OFFSET(field) \
offsetof(struct kgsl_devmemstore, field)
#define KGSL_MEMSTORE_OFFSET(ctxt_id, field) \
((ctxt_id)*sizeof(struct kgsl_devmemstore) + \
offsetof(struct kgsl_devmemstore, field))
/* timestamp id*/
enum kgsl_timestamp_type {
@ -268,6 +273,14 @@ struct kgsl_device_waittimestamp {
#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \
_IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp)
struct kgsl_device_waittimestamp_ctxtid {
unsigned int context_id;
unsigned int timestamp;
unsigned int timeout;
};
#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
/* issue indirect commands to the GPU.
* drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
@ -361,6 +374,26 @@ struct kgsl_map_user_mem {
#define IOCTL_KGSL_MAP_USER_MEM \
_IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)
struct kgsl_cmdstream_readtimestamp_ctxtid {
unsigned int context_id;
unsigned int type;
unsigned int timestamp; /*output param */
};
#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \
_IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid)
struct kgsl_cmdstream_freememontimestamp_ctxtid {
unsigned int context_id;
unsigned int gpuaddr;
unsigned int type;
unsigned int timestamp;
};
#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID \
_IOW(KGSL_IOC_TYPE, 0x17, \
struct kgsl_cmdstream_freememontimestamp_ctxtid)
/* add a block of pmem or fb into the GPU address space */
struct kgsl_sharedmem_from_pmem {
int pmem_fd;
@ -504,6 +537,14 @@ struct kgsl_timestamp_event_genlock {
int handle; /* Handle of the genlock lock to release */
};
/*
* Set a property within the kernel. Uses the same structure as
* IOCTL_KGSL_GETPROPERTY
*/
#define IOCTL_KGSL_SETPROPERTY \
_IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,