diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a73caaf6..f35b1588 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -17,7 +17,7 @@ endif OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S GZFLAGS :=-9 -#KBUILD_CFLAGS +=-pipe +KBUILD_CFLAGS +=-pipe # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: KBUILD_CFLAGS +=$(call cc-option,-marm,) diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index d06a9447..9b39d2b8 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -32,7 +32,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_LOCALVERSION="_tytung_HWA_r3.5" +CONFIG_LOCALVERSION="_tytung_HWA_r3.3_JB" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_BZIP2=y 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/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index 82e110ce..028a1c7c 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -992,7 +992,7 @@ static void setup_fb_info(struct msmfb_info *msmfb) int r; /* finish setting up the fb_info struct */ - strncpy(fb_info->fix.id, "msmfb", 16); + strncpy(fb_info->fix.id, "msmfb31_0", 16); fb_info->fix.ypanstep = 1; fb_info->fbops = &msmfb_ops; 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, diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index a933facc..dcedc554 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -1,6 +1,7 @@ /* include/linux/msm_mdp.h * * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2012 Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -15,25 +16,90 @@ #define _MSM_MDP_H_ #include +#include #define MSMFB_IOCTL_MAGIC 'm' #define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, 1, unsigned int) #define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int) +#define MSMFB_SUSPEND_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 128, unsigned int) +#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int) +#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor) +#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap) +#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram_data) +/* new ioctls's for set/get ccs matrix */ +#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs) +#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs) +#define MSMFB_OVERLAY_SET _IOWR(MSMFB_IOCTL_MAGIC, 135, \ + struct mdp_overlay) +#define MSMFB_OVERLAY_UNSET _IOW(MSMFB_IOCTL_MAGIC, 136, unsigned int) +#define MSMFB_OVERLAY_PLAY _IOW(MSMFB_IOCTL_MAGIC, 137, \ + struct msmfb_overlay_data) +#define MSMFB_GET_PAGE_PROTECTION _IOR(MSMFB_IOCTL_MAGIC, 138, \ + struct mdp_page_protection) +#define MSMFB_SET_PAGE_PROTECTION _IOW(MSMFB_IOCTL_MAGIC, 139, \ + struct mdp_page_protection) +#define MSMFB_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \ + struct mdp_overlay) +#define MSMFB_OVERLAY_PLAY_ENABLE _IOW(MSMFB_IOCTL_MAGIC, 141, unsigned int) +#define MSMFB_OVERLAY_BLT _IOWR(MSMFB_IOCTL_MAGIC, 142, \ + struct msmfb_overlay_blt) +#define MSMFB_OVERLAY_BLT_OFFSET _IOW(MSMFB_IOCTL_MAGIC, 143, unsigned int) +#define MSMFB_HISTOGRAM_START _IOR(MSMFB_IOCTL_MAGIC, 144, \ + struct mdp_histogram_start_req) +#define MSMFB_HISTOGRAM_STOP _IOR(MSMFB_IOCTL_MAGIC, 145, unsigned int) +#define MSMFB_NOTIFY_UPDATE _IOW(MSMFB_IOCTL_MAGIC, 146, unsigned int) + +#define MSMFB_OVERLAY_3D _IOWR(MSMFB_IOCTL_MAGIC, 147, \ + struct msmfb_overlay_3d) + +#define MSMFB_MIXER_INFO _IOWR(MSMFB_IOCTL_MAGIC, 148, \ + struct msmfb_mixer_info_req) +#define MSMFB_OVERLAY_PLAY_WAIT _IOWR(MSMFB_IOCTL_MAGIC, 149, \ + struct msmfb_overlay_data) +#define MSMFB_WRITEBACK_INIT _IO(MSMFB_IOCTL_MAGIC, 150) +#define MSMFB_WRITEBACK_START _IO(MSMFB_IOCTL_MAGIC, 151) +#define MSMFB_WRITEBACK_STOP _IO(MSMFB_IOCTL_MAGIC, 152) +#define MSMFB_WRITEBACK_QUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 153, \ + struct msmfb_data) +#define MSMFB_WRITEBACK_DEQUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 154, \ + struct msmfb_data) +#define MSMFB_WRITEBACK_TERMINATE _IO(MSMFB_IOCTL_MAGIC, 155) +#define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp) + +#define FB_TYPE_3D_PANEL 0x10101010 +#define MDP_IMGTYPE2_START 0x10000 +#define MSMFB_DRIVER_VERSION 0xF9E8D701 enum { - MDP_RGB_565, /* RGB 565 planar */ + NOTIFY_UPDATE_START, + NOTIFY_UPDATE_STOP, +}; + +enum { + MDP_RGB_565, /* RGB 565 planer */ MDP_XRGB_8888, /* RGB 888 padded */ - MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planar w/ Cb is in MSB */ + MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */ + MDP_Y_CBCR_H2V2_ADRENO, MDP_ARGB_8888, /* ARGB 888 */ - MDP_RGB_888, /* RGB 888 planar */ - MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planar w/ Cr is in MSB */ + MDP_RGB_888, /* RGB 888 planer */ + MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */ MDP_YCRYCB_H2V1, /* YCrYCb interleave */ - MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planar w/ Cr is in MSB */ - MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planar w/ Cr is in MSB */ + MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ MDP_RGBA_8888, /* ARGB 888 */ MDP_BGRA_8888, /* ABGR 888 */ MDP_RGBX_8888, /* RGBX 888 */ - MDP_IMGTYPE_LIMIT /* Non valid image type after this enum */ + MDP_Y_CRCB_H2V2_TILE, /* Y and CrCb, pseudo planer tile */ + MDP_Y_CBCR_H2V2_TILE, /* Y and CbCr, pseudo planer tile */ + MDP_Y_CR_CB_H2V2, /* Y, Cr and Cb, planar */ + MDP_Y_CR_CB_GH2V2, /* Y, Cr and Cb, planar aligned to Android YV12 */ + MDP_Y_CB_CR_H2V2, /* Y, Cb and Cr, planar */ + MDP_Y_CRCB_H1V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_Y_CBCR_H1V1, /* Y and CbCr, pseduo planer w/ Cb is in MSB */ + MDP_IMGTYPE_LIMIT, + MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */ + MDP_FB_FORMAT, /* framebuffer format */ + MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */ }; enum { @@ -41,24 +107,57 @@ enum { FB_IMG, }; -/* flag values */ +enum { + HSIC_HUE = 0, + HSIC_SAT, + HSIC_INT, + HSIC_CON, + NUM_HSIC_PARAM, +}; + +/* mdp_blit_req flag values */ #define MDP_ROT_NOP 0 #define MDP_FLIP_LR 0x1 #define MDP_FLIP_UD 0x2 #define MDP_ROT_90 0x4 #define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR) #define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR) -#define MDP_ROT_MASK 0x7 #define MDP_DITHER 0x8 #define MDP_BLUR 0x10 #define MDP_BLEND_FG_PREMULT 0x20000 +#define MDP_DEINTERLACE 0x80000000 +#define MDP_SHARPENING 0x40000000 +#define MDP_NO_DMA_BARRIER_START 0x20000000 +#define MDP_NO_DMA_BARRIER_END 0x10000000 +#define MDP_NO_BLIT 0x08000000 +#define MDP_BLIT_WITH_DMA_BARRIERS 0x000 +#define MDP_BLIT_WITH_NO_DMA_BARRIERS \ + (MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END) +#define MDP_BLIT_SRC_GEM 0x04000000 +#define MDP_BLIT_DST_GEM 0x02000000 +#define MDP_BLIT_NON_CACHED 0x01000000 +#define MDP_OV_PIPE_SHARE 0x00800000 +#define MDP_DEINTERLACE_ODD 0x00400000 +#define MDP_OV_PLAY_NOWAIT 0x00200000 +#define MDP_SOURCE_ROTATED_90 0x00100000 +#define MDP_DPP_HSIC 0x00080000 +#define MDP_BACKEND_COMPOSITION 0x00040000 +#define MDP_BORDERFILL_SUPPORTED 0x00010000 +#define MDP_SECURE_OVERLAY_SESSION 0x00008000 +#define MDP_MEMORY_ID_TYPE_FB 0x00001000 #define MDP_TRANSP_NOP 0xffffffff #define MDP_ALPHA_NOP 0xff -/* drewis: added for android 4.0 */ -#define MDP_BLIT_NON_CACHED 0x01000000 -/* drewis: end */ +#define MDP_FB_PAGE_PROTECTION_NONCACHED (0) +#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1) +#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4) +/* Sentinel: Don't use! */ +#define MDP_FB_PAGE_PROTECTION_INVALID (5) +/* Count of the number of MDP_FB_PAGE_PROTECTION_... values. */ +#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5) struct mdp_rect { uint32_t x; @@ -73,8 +172,41 @@ struct mdp_img { uint32_t format; uint32_t offset; int memory_id; /* the file descriptor */ + uint32_t priv; }; +/* + * {3x3} + {3} ccs matrix + */ + +#define MDP_CCS_RGB2YUV 0 +#define MDP_CCS_YUV2RGB 1 + +#define MDP_CCS_SIZE 9 +#define MDP_BV_SIZE 3 + +struct mdp_ccs { + int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */ + uint16_t ccs[MDP_CCS_SIZE]; /* 3x3 color coefficients */ + uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */ +}; + +struct mdp_csc { + int id; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +/* The version of the mdp_blit_req structure so that + * user applications can selectively decide which functionality + * to include + */ + +#define MDP_BLIT_REQ_VERSION 2 + struct mdp_blit_req { struct mdp_img src; struct mdp_img dst; @@ -83,6 +215,7 @@ struct mdp_blit_req { uint32_t alpha; uint32_t transp_mask; uint32_t flags; + int sharpening_strength; /* -127 <--> 127, default 64 */ }; struct mdp_blit_req_list { @@ -90,4 +223,289 @@ struct mdp_blit_req_list { struct mdp_blit_req req[]; }; +#define MSMFB_DATA_VERSION 2 + +struct msmfb_data { + uint32_t offset; + int memory_id; + int id; + uint32_t flags; + uint32_t priv; + uint32_t iova; +}; + +#define MSMFB_NEW_REQUEST -1 + +struct msmfb_overlay_data { + uint32_t id; + struct msmfb_data data; + uint32_t version_key; + struct msmfb_data plane1_data; + struct msmfb_data plane2_data; +}; + +struct msmfb_img { + uint32_t width; + uint32_t height; + uint32_t format; +}; + +#define MSMFB_WRITEBACK_DEQUEUE_BLOCKING 0x1 +struct msmfb_writeback_data { + struct msmfb_data buf_info; + struct msmfb_img img; +}; + +struct dpp_ctrl { + /* + *'sharp_strength' has inputs = -128 <-> 127 + * Increasingly positive values correlate with increasingly sharper + * picture. Increasingly negative values correlate with increasingly + * smoothed picture. + */ + int8_t sharp_strength; + int8_t hsic_params[NUM_HSIC_PARAM]; +}; + +struct mdp_overlay { + struct msmfb_img src; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t z_order; /* stage number */ + uint32_t is_fg; /* control alpha & transp */ + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; + uint32_t id; + uint32_t user_data[8]; + struct dpp_ctrl dpp; +}; + +struct msmfb_overlay_3d { + uint32_t is_3d; + uint32_t width; + uint32_t height; +}; + + +struct msmfb_overlay_blt { + uint32_t enable; + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t bpp; +}; + +struct mdp_histogram { + uint32_t frame_cnt; + uint32_t bin_cnt; + uint32_t *r; + uint32_t *g; + uint32_t *b; +}; + + +/* + + mdp_block_type defines the identifiers for each of pipes in MDP 4.3 + + MDP_BLOCK_RESERVED is provided for backward compatibility and is + deprecated. It corresponds to DMA_P. So MDP_BLOCK_DMA_P should be used + instead. + +*/ + +enum { + MDP_BLOCK_RESERVED = 0, + MDP_BLOCK_OVERLAY_0, + MDP_BLOCK_OVERLAY_1, + MDP_BLOCK_VG_1, + MDP_BLOCK_VG_2, + MDP_BLOCK_RGB_1, + MDP_BLOCK_RGB_2, + MDP_BLOCK_DMA_P, + MDP_BLOCK_DMA_S, + MDP_BLOCK_DMA_E, + MDP_BLOCK_MAX, +}; + +/* +mdp_histogram_start_req is used to provide the parameters for +histogram start request +*/ + +struct mdp_histogram_start_req { + uint32_t block; + uint8_t frame_cnt; + uint8_t bit_mask; + uint8_t num_bins; +}; + + +/* + + mdp_histogram_data is used to return the histogram data, once + the histogram is done/stopped/cance + + */ + + +struct mdp_histogram_data { + uint32_t block; + uint8_t bin_cnt; + uint32_t *c0; + uint32_t *c1; + uint32_t *c2; + uint32_t *extra_info; +}; + +struct mdp_pcc_coeff { + uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1; +}; + +struct mdp_pcc_cfg_data { + uint32_t block; + uint32_t ops; + struct mdp_pcc_coeff r, g, b; +}; + +#define MDP_CSC_FLAG_ENABLE 0x1 +#define MDP_CSC_FLAG_YUV_IN 0x2 +#define MDP_CSC_FLAG_YUV_OUT 0x4 + +struct mdp_csc_cfg { + /* flags for enable CSC, toggling RGB,YUV input/output */ + uint32_t flags; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +struct mdp_csc_cfg_data { + uint32_t block; + struct mdp_csc_cfg csc_data; +}; + +enum { + mdp_lut_igc, + mdp_lut_pgc, + mdp_lut_hist, + mdp_lut_max, +}; + + +struct mdp_igc_lut_data { + uint32_t block; + uint32_t len, ops; + uint32_t *c0_c1_data; + uint32_t *c2_data; +}; + +struct mdp_ar_gc_lut_data { + uint32_t x_start; + uint32_t slope; + uint32_t offset; +}; + +struct mdp_pgc_lut_data { + uint32_t block; + uint32_t flags; + uint8_t num_r_stages; + uint8_t num_g_stages; + uint8_t num_b_stages; + struct mdp_ar_gc_lut_data *r_data; + struct mdp_ar_gc_lut_data *g_data; + struct mdp_ar_gc_lut_data *b_data; +}; + + +struct mdp_hist_lut_data { + uint32_t block; + uint32_t ops; + uint32_t len; + uint32_t *data; +}; + + +struct mdp_lut_cfg_data { + uint32_t lut_type; + union { + struct mdp_igc_lut_data igc_lut_data; + struct mdp_pgc_lut_data pgc_lut_data; + struct mdp_hist_lut_data hist_lut_data; + } data; +}; + +struct mdp_qseed_cfg_data { + uint32_t block; + uint32_t table_num; + uint32_t ops; + uint32_t len; + uint32_t *data; +}; + + +enum { + mdp_op_pcc_cfg, + mdp_op_csc_cfg, + mdp_op_lut_cfg, + mdp_op_qseed_cfg, + mdp_op_max, +}; + +struct msmfb_mdp_pp { + uint32_t op; + union { + struct mdp_pcc_cfg_data pcc_cfg_data; + struct mdp_csc_cfg_data csc_cfg_data; + struct mdp_lut_cfg_data lut_cfg_data; + struct mdp_qseed_cfg_data qseed_cfg_data; + } data; +}; + + +struct mdp_page_protection { + uint32_t page_protection; +}; + + +struct mdp_mixer_info { + int pndx; + int pnum; + int ptype; + int mixer_num; + int z_order; +}; + +#define MAX_PIPE_PER_MIXER 4 + +struct msmfb_mixer_info_req { + int mixer_num; + int cnt; + struct mdp_mixer_info info[MAX_PIPE_PER_MIXER]; +}; + +enum { + DISPLAY_SUBSYSTEM_ID, + ROTATOR_SUBSYSTEM_ID, +}; + +#ifdef __KERNEL__ + +/* get the framebuffer physical address information */ +int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num, + int subsys_id); +struct fb_info *msm_fb_get_writeback_fb(void); +int msm_fb_writeback_init(struct fb_info *info); +int msm_fb_writeback_start(struct fb_info *info); +int msm_fb_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_stop(struct fb_info *info); +int msm_fb_writeback_terminate(struct fb_info *info); +#endif + #endif /* _MSM_MDP_H_ */ diff --git a/mm/ashmem.c b/mm/ashmem.c old mode 100644 new mode 100755