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:
parent
cad19fbe99
commit
2f3f4d14f9
6
drivers/gpu/msm/adreno.h
Normal file → Executable file
6
drivers/gpu/msm/adreno.h
Normal file → Executable 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 *);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
6
drivers/gpu/msm/adreno_drawctxt.h
Normal file → Executable 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
31
drivers/gpu/msm/adreno_ringbuffer.c
Normal file → Executable 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
1
include/linux/msm_kgsl.h
Normal file → Executable 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user