diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 4020fefd..4e434e4c 100755 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -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, ×tamp); else if (type == KGSL_TIMESTAMP_RETIRED) kgsl_sharedmem_readl(&device->memstore, ×tamp, - KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)); + KGSL_MEMSTORE_OFFSET(context_id, + eoptimestamp)); rmb(); return timestamp; diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c index cc611779..dc43062e 100755 --- a/drivers/gpu/msm/adreno_a2xx.c +++ b/drivers/gpu/msm/adreno_a2xx.c @@ -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 */ diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index cbc7bed4..507ad02e 100755 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -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"); } diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 87f9efe4..fc4789ad 100755 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -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: diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 50ee3450..61198ebd 100755 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -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; diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c index 7e073fd9..427741f1 100755 --- a/drivers/gpu/msm/adreno_postmortem.c +++ b/drivers/gpu/msm/adreno_postmortem.c @@ -14,6 +14,7 @@ #include #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); diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 71f239cc..da80576f 100755 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -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++] = diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index d0110b9f..7c93b3b5 100755 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -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]; }; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e7c4ff8b..491944ba 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -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, ¶m->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, ¶m->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; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 3f9ff843..aff17338 100755 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -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; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index ff78ae3f..45e41d91 100755 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -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); diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c old mode 100644 new mode 100755 index e7a1d521..688f23d8 --- a/drivers/gpu/msm/z180.c +++ b/drivers/gpu/msm/z180.c @@ -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) diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h index 36357e08..92b41a5d 100755 --- a/include/linux/msm_kgsl.h +++ b/include/linux/msm_kgsl.h @@ -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,