msm: kgsl: Add support for the preamble context flag

Userspace will set a flag in the context if preambles are in use. If
they are, we can safely skip save and restore commands for the
context. GMEM save/restore is still required.  To improve performance,
preamble commands are skipped when the context hasn't changed since
the last issueibcmds.

from Code Aurora
This commit is contained in:
securecrt 2012-06-19 14:00:07 +08:00
parent cad19fbe99
commit 2f3f4d14f9
6 changed files with 133 additions and 69 deletions

6
drivers/gpu/msm/adreno.h Normal file → Executable file
View File

@ -24,6 +24,7 @@
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_NO_TS_CMP 0x00000002
#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
@ -67,10 +68,7 @@ struct adreno_device {
};
struct adreno_gpudev {
int (*ctxt_gpustate_shadow)(struct adreno_device *,
struct adreno_context *);
int (*ctxt_gmem_shadow)(struct adreno_device *,
struct adreno_context *);
int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
irqreturn_t (*irq_handler)(struct adreno_device *);

View File

@ -546,6 +546,7 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
unsigned int addr = shadow->gmemshadow.gpuaddr;
unsigned int offset = (addr - (addr & 0xfffff000)) / bytesperpixel;
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
/* Store TP0_CHICKEN register */
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
*cmds++ = REG_TP0_CHICKEN;
@ -554,6 +555,7 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0;
}
/* Set TP0_CHICKEN to zero */
*cmds++ = cp_type0_packet(REG_TP0_CHICKEN, 1);
@ -755,6 +757,7 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev,
unsigned int *cmds = shadow->gmem_restore_commands;
unsigned int *start = cmds;
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
/* Store TP0_CHICKEN register */
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
*cmds++ = REG_TP0_CHICKEN;
@ -762,6 +765,7 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev,
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0;
}
/* Set TP0_CHICKEN to zero */
*cmds++ = cp_type0_packet(REG_TP0_CHICKEN, 1);
@ -1089,7 +1093,8 @@ static void build_regrestore_cmds(struct adreno_device *adreno_dev,
}
static void
build_shader_save_restore_cmds(struct adreno_context *drawctxt)
build_shader_save_restore_cmds(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
unsigned int *cmd = tmp_ctx.cmd;
unsigned int *save, *restore, *fixup;
@ -1219,45 +1224,22 @@ build_shader_save_restore_cmds(struct adreno_context *drawctxt)
}
/* create buffers for saving/restoring registers, constants, & GMEM */
static int a2xx_ctxt_gpustate_shadow(struct adreno_device *adreno_dev,
static int a2xx_create_gpustate_shadow(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
int result;
/* Allocate vmalloc memory to store the gpustate */
result = kgsl_allocate(&drawctxt->gpustate,
drawctxt->pagetable, CONTEXT_SIZE);
if (result)
return result;
drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;
/* Blank out h/w register, constant, and command buffer shadows. */
kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);
/* set-up command and vertex buffer pointers */
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
/* build indirect command buffers to save & restore regs/constants */
adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT);
build_regrestore_cmds(adreno_dev, drawctxt);
build_regsave_cmds(adreno_dev, drawctxt);
build_shader_save_restore_cmds(drawctxt);
build_shader_save_restore_cmds(adreno_dev, drawctxt);
kgsl_cache_range_op(&drawctxt->gpustate,
KGSL_CACHE_OP_FLUSH);
kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
drawctxt->gpustate.gpuaddr,
drawctxt->gpustate.size, false);
return 0;
}
/* create buffers for saving/restoring registers, constants, & GMEM */
static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
int result;
@ -1284,6 +1266,7 @@ static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
&tmp_ctx.cmd);
/* build TP0_CHICKEN register restore command buffer */
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE))
tmp_ctx.cmd = build_chicken_restore_cmds(drawctxt);
/* build indirect command buffers to save & restore gmem */
@ -1309,7 +1292,61 @@ static int a2xx_ctxt_gmem_shadow(struct adreno_device *adreno_dev,
return 0;
}
static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
int ret;
/*
* Allocate memory for the GPU state and the context commands.
* Despite the name, this is much more then just storage for
* the gpustate. This contains command space for gmem save
* and texture and vertex buffer storage too
*/
ret = kgsl_allocate(&drawctxt->gpustate,
drawctxt->pagetable, CONTEXT_SIZE);
if (ret)
return ret;
kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0,
CONTEXT_SIZE);
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
ret = a2xx_create_gpustate_shadow(adreno_dev, drawctxt);
if (ret)
goto done;
drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
}
if (!(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC)) {
ret = a2xx_create_gmem_shadow(adreno_dev, drawctxt);
if (ret)
goto done;
}
/* Flush and sync the gpustate memory */
kgsl_cache_range_op(&drawctxt->gpustate,
KGSL_CACHE_OP_FLUSH);
kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
drawctxt->gpustate.gpuaddr,
drawctxt->gpustate.size, false);
done:
if (ret)
kgsl_sharedmem_free(&drawctxt->gpustate);
return ret;
}
static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
@ -1321,25 +1358,28 @@ static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
KGSL_CTXT_WARN(device,
"Current active context has caused gpu hang\n");
KGSL_CTXT_INFO(device,
"active context flags %08x\n", context->flags);
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
/* save registers and constants. */
adreno_ringbuffer_issuecmds(device, 0, context->reg_save, 3);
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->reg_save, 3);
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
/* save shader partitioning and instructions. */
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
adreno_ringbuffer_issuecmds(device,
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
/* fixup shader partitioning parameter for
/*
* fixup shader partitioning parameter for
* SET_SHADER_BASES.
*/
adreno_ringbuffer_issuecmds(device, 0,
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->shader_fixup, 3);
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
}
}
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
@ -1350,14 +1390,16 @@ static void a2xx_ctxt_save(struct adreno_device *adreno_dev,
context->context_gmem_shadow.gmem_save, 3);
/* Restore TP0_CHICKEN */
adreno_ringbuffer_issuecmds(device, 0,
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
}
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
}
}
static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
@ -1377,7 +1419,7 @@ static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
cmds[3] = device->memstore.gpuaddr +
KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
cmds[4] = (unsigned int) context;
adreno_ringbuffer_issuecmds(device, 0, cmds, 5);
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
kgsl_mmu_setstate(device, context->pagetable);
#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
@ -1393,27 +1435,34 @@ static void a2xx_ctxt_restore(struct adreno_device *adreno_dev,
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_restore, 3);
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
/* Restore TP0_CHICKEN */
adreno_ringbuffer_issuecmds(device, 0,
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
}
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
/* restore registers and constants. */
adreno_ringbuffer_issuecmds(device, 0,
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->reg_restore, 3);
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
adreno_ringbuffer_issuecmds(device, 0,
adreno_ringbuffer_issuecmds(device,
KGSL_CMD_FLAGS_NONE,
context->shader_restore, 3);
}
}
if (adreno_is_a20x(adreno_dev)) {
cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
cmds[1] = context->bin_base_offset;
adreno_ringbuffer_issuecmds(device, 0, cmds, 2);
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
cmds, 2);
}
}
@ -1610,10 +1659,9 @@ static void a2xx_irq_control(struct adreno_device *adreno_dev, int state)
}
struct adreno_gpudev adreno_a2xx_gpudev = {
.ctxt_gpustate_shadow = a2xx_ctxt_gpustate_shadow,
.ctxt_gmem_shadow = a2xx_ctxt_gmem_shadow,
.ctxt_save = a2xx_ctxt_save,
.ctxt_restore = a2xx_ctxt_restore,
.ctxt_create = a2xx_drawctxt_create,
.ctxt_save = a2xx_drawctxt_save,
.ctxt_restore = a2xx_drawctxt_restore,
.irq_handler = a2xx_irq_handler,
.irq_control = a2xx_irq_control,
};

View File

@ -139,27 +139,19 @@ int adreno_drawctxt_create(struct kgsl_device *device,
drawctxt->pagetable = pagetable;
drawctxt->bin_base_offset = 0;
/* FIXME: Deal with preambles */
if (flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
ret = adreno_dev->gpudev->ctxt_gpustate_shadow(adreno_dev, drawctxt);
if (flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
/* Save the shader instruction memory on context switching */
drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
if (!(flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
/* create gmem shadow */
ret = adreno_dev->gpudev->ctxt_gmem_shadow(adreno_dev,
drawctxt);
if (ret != 0)
goto err;
}
context->devctxt = drawctxt;
return 0;
err:
kgsl_sharedmem_free(&drawctxt->gpustate);
kfree(drawctxt);
return ret;
}

6
drivers/gpu/msm/adreno_drawctxt.h Normal file → Executable file
View File

@ -1,4 +1,4 @@
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -30,12 +30,16 @@
#define CTXT_FLAGS_GMEM_SAVE 0x00000200
/* gmem can be restored from shadow */
#define CTXT_FLAGS_GMEM_RESTORE 0x00000400
/* preamble packed in cmdbuffer for context switching */
#define CTXT_FLAGS_PREAMBLE 0x00000800
/* shader must be copied to shadow */
#define CTXT_FLAGS_SHADER_SAVE 0x00002000
/* shader can be restored from shadow */
#define CTXT_FLAGS_SHADER_RESTORE 0x00004000
/* Context has caused a GPU hang */
#define CTXT_FLAGS_GPU_HANG 0x00008000
/* Specifies there is no need to save GMEM */
#define CTXT_FLAGS_NOGMEMALLOC 0x00010000
struct kgsl_device;
struct adreno_device;

31
drivers/gpu/msm/adreno_ringbuffer.c Normal file → Executable file
View File

@ -1,4 +1,4 @@
/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -391,7 +391,6 @@ void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
if (rb->flags & KGSL_FLAGS_STARTED) {
/* ME_HALT */
adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
rb->flags &= ~KGSL_FLAGS_STARTED;
}
}
@ -560,6 +559,7 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int *cmds;
unsigned int i;
struct adreno_context *drawctxt;
unsigned int start_index = 0;
if (device->state & KGSL_STATE_HUNG)
return -EBUSY;
@ -582,7 +582,16 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
" submission, size %x\n", numibs * 3);
return -ENOMEM;
}
for (i = 0; i < numibs; i++) {
/*When preamble is enabled, the preamble buffer with state restoration
commands are stored in the first node of the IB chain. We can skip that
if a context switch hasn't occured */
if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
adreno_dev->drawctxt_active == drawctxt)
start_index = 1;
for (i = start_index; i < numibs; i++) {
(void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
@ -739,8 +748,20 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
BUG_ON((copy_rb_contents == 0) &&
(value == cur_context));
/*
* If other context switches were already lost and
* and the current context is the one that is hanging,
* then we cannot recover. Print an error message
* and leave.
*/
if ((copy_rb_contents == 0) && (value == cur_context)) {
KGSL_DRV_ERR(device, "GPU recovery could not "
"find the previous context\n");
return -EINVAL;
}
/*
* If we were copying the commands and got to this point
* then we need to remove the 3 commands that appear

1
include/linux/msm_kgsl.h Normal file → Executable file
View File

@ -42,6 +42,7 @@
#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
/* Memory allocayion flags */
#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000