forked from rubenslte/android_kernel_samsung_msm8226
msm: kgsl: embed kgsl_context struct in adreno_context struct
Having a separate allocated struct for the device specific context makes ownership unclear, which could lead to reference counting problems or invalid pointers. Also, duplicate members were starting to appear in adreno_context because there wasn't a safe way to reach the kgsl_context from some parts of the adreno code. This can now be done via container_of(). This change alters the lifecycle of the context->id, which is now freed when the context reference count hits zero rather than in kgsl_context_detach(). It also changes the context creation and destruction sequence. The device specific code must allocate a structure containing a struct kgsl_context and passes a pointer it to kgsl_init_context() before doing any device specific initialization. There is also a separate drawctxt_detach() callback for doing device specific cleanup. This is separate from freeing memory, which is done by the drawctxt_destroy() callback. Change-Id: I7d238476a3bfec98fd8dbc28971cf3187a81dac2 Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
parent
708089fe3b
commit
0ca32f2a38
+45
-36
@@ -865,7 +865,7 @@ static void adreno_iommu_setstate(struct kgsl_device *device,
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
adreno_ctx = context->devctxt;
|
||||
adreno_ctx = ADRENO_CONTEXT(context);
|
||||
|
||||
if (kgsl_mmu_enable_clk(&device->mmu,
|
||||
KGSL_IOMMU_CONTEXT_USER))
|
||||
@@ -939,7 +939,7 @@ static void adreno_gpummu_setstate(struct kgsl_device *device,
|
||||
context = kgsl_context_get(device, context_id);
|
||||
if (context == NULL)
|
||||
return;
|
||||
adreno_ctx = context->devctxt;
|
||||
adreno_ctx = ADRENO_CONTEXT(context);
|
||||
|
||||
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
|
||||
/* wait for graphics pipe to be idle */
|
||||
@@ -1912,7 +1912,7 @@ static int _mark_context_status(int id, void *ptr, void *data)
|
||||
{
|
||||
unsigned int ft_status = *((unsigned int *) data);
|
||||
struct kgsl_context *context = ptr;
|
||||
struct adreno_context *adreno_context = context->devctxt;
|
||||
struct adreno_context *adreno_context = ADRENO_CONTEXT(context);
|
||||
|
||||
if (ft_status) {
|
||||
context->reset_status =
|
||||
@@ -1953,7 +1953,7 @@ static int _set_max_ts(int id, void *ptr, void *data)
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
|
||||
struct kgsl_context *context = ptr;
|
||||
struct adreno_context *drawctxt = context->devctxt;
|
||||
struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
|
||||
|
||||
if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
|
||||
kgsl_sharedmem_writel(device, &device->memstore,
|
||||
@@ -2219,7 +2219,7 @@ static void adreno_setup_ft_data(struct kgsl_device *device,
|
||||
}
|
||||
|
||||
if (context) {
|
||||
adreno_context = context->devctxt;
|
||||
adreno_context = ADRENO_CONTEXT(context);
|
||||
if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
|
||||
if (ft_data->ib1) {
|
||||
ret = _find_hanging_ib_sequence(rb,
|
||||
@@ -2348,11 +2348,9 @@ _adreno_ft_restart_device(struct kgsl_device *device,
|
||||
}
|
||||
|
||||
reset_done:
|
||||
if (context) {
|
||||
struct adreno_context *adreno_context = context->devctxt;
|
||||
kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
|
||||
KGSL_MEMSTORE_GLOBAL);
|
||||
}
|
||||
if (context)
|
||||
kgsl_mmu_setstate(&device->mmu, context->pagetable,
|
||||
KGSL_MEMSTORE_GLOBAL);
|
||||
|
||||
/* If iommu is used then we need to make sure that the iommu clocks
|
||||
* are on since there could be commands in pipeline that touch iommu */
|
||||
@@ -2471,7 +2469,7 @@ _adreno_ft(struct kgsl_device *device,
|
||||
}
|
||||
} else {
|
||||
no_context_ft = 0;
|
||||
adreno_context = context->devctxt;
|
||||
adreno_context = ADRENO_CONTEXT(context);
|
||||
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
|
||||
/*
|
||||
* set the invalid ts flag to 0 for this context since we have
|
||||
@@ -2527,16 +2525,16 @@ _adreno_ft(struct kgsl_device *device,
|
||||
goto play_good_cmds;
|
||||
}
|
||||
|
||||
/* Do not try the reply if hang is due to a pagefault */
|
||||
if (adreno_context && adreno_context->pagefault) {
|
||||
/* Do not try to replay if hang is due to a pagefault */
|
||||
if (context && test_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv)) {
|
||||
/* Resume MMU */
|
||||
mmu->mmu_ops->mmu_pagefault_resume(mmu);
|
||||
if ((ft_data->context_id == adreno_context->id) &&
|
||||
(ft_data->global_eop == adreno_context->pagefault_ts)) {
|
||||
if ((ft_data->context_id == context->id) &&
|
||||
(ft_data->global_eop == context->pagefault_ts)) {
|
||||
ft_data->ft_policy &= ~KGSL_FT_REPLAY;
|
||||
KGSL_FT_ERR(device, "MMU fault skipping replay\n");
|
||||
}
|
||||
adreno_context->pagefault = 0;
|
||||
clear_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
|
||||
}
|
||||
|
||||
if (ft_data->ft_policy & KGSL_FT_REPLAY) {
|
||||
@@ -2652,8 +2650,7 @@ play_good_cmds:
|
||||
ft_data->last_valid_ctx_id);
|
||||
|
||||
if (last_ctx)
|
||||
adreno_dev->drawctxt_active = last_ctx->devctxt;
|
||||
|
||||
adreno_dev->drawctxt_active = ADRENO_CONTEXT(last_ctx);
|
||||
kgsl_context_put(last_ctx);
|
||||
}
|
||||
|
||||
@@ -2720,7 +2717,7 @@ adreno_ft(struct kgsl_device *device,
|
||||
/* Restore correct states after fault tolerance */
|
||||
if (adreno_dev->drawctxt_active)
|
||||
device->mmu.hwpagetable =
|
||||
adreno_dev->drawctxt_active->pagetable;
|
||||
adreno_dev->drawctxt_active->base.pagetable;
|
||||
else
|
||||
device->mmu.hwpagetable = device->mmu.defaultpagetable;
|
||||
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
|
||||
@@ -3119,21 +3116,20 @@ struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
|
||||
phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size)
|
||||
{
|
||||
struct kgsl_context *context;
|
||||
struct adreno_context *adreno_context = NULL;
|
||||
int next = 0;
|
||||
struct kgsl_memdesc *desc = NULL;
|
||||
|
||||
|
||||
read_lock(&device->context_lock);
|
||||
while (1) {
|
||||
context = idr_get_next(&device->context_idr, &next);
|
||||
if (context == NULL)
|
||||
break;
|
||||
|
||||
adreno_context = (struct adreno_context *)context->devctxt;
|
||||
|
||||
if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable,
|
||||
if (kgsl_mmu_pt_equal(&device->mmu, context->pagetable,
|
||||
pt_base)) {
|
||||
struct adreno_context *adreno_context;
|
||||
|
||||
adreno_context = ADRENO_CONTEXT(context);
|
||||
desc = &adreno_context->gpustate;
|
||||
if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
|
||||
break;
|
||||
@@ -3267,9 +3263,10 @@ static void adreno_regwrite(struct kgsl_device *device,
|
||||
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 (k_ctxt->id == KGSL_CONTEXT_INVALID || a_ctxt == NULL)
|
||||
struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
|
||||
if (kgsl_context_detached(k_ctxt))
|
||||
context_id = KGSL_CONTEXT_INVALID;
|
||||
else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
|
||||
context_id = k_ctxt->id;
|
||||
@@ -3340,7 +3337,8 @@ static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
|
||||
*/
|
||||
|
||||
if (context && device->state != KGSL_STATE_SLUMBER) {
|
||||
adreno_ringbuffer_issuecmds(device, context->devctxt,
|
||||
adreno_ringbuffer_issuecmds(device,
|
||||
ADRENO_CONTEXT(context),
|
||||
KGSL_CMD_FLAGS_GET_INT, NULL, 0);
|
||||
}
|
||||
}
|
||||
@@ -3400,6 +3398,7 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
unsigned int curr_context_id = 0;
|
||||
static struct adreno_context *curr_context;
|
||||
static struct kgsl_context *context;
|
||||
static char pid_name[TASK_COMM_LEN] = "unknown";
|
||||
|
||||
if (!adreno_dev->fast_hang_detect)
|
||||
fast_hang_detected = 0;
|
||||
@@ -3463,8 +3462,13 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
|
||||
if (curr_global_ts == prev_global_ts) {
|
||||
|
||||
/* Get the current context here */
|
||||
if (context == NULL) {
|
||||
/* If we don't already have a good context, get it. */
|
||||
if (kgsl_context_detached(context)) {
|
||||
kgsl_context_put(context);
|
||||
context = NULL;
|
||||
curr_context = NULL;
|
||||
strlcpy(pid_name, "unknown", sizeof(pid_name));
|
||||
|
||||
kgsl_sharedmem_readl(&device->memstore,
|
||||
&curr_context_id,
|
||||
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
|
||||
@@ -3474,8 +3478,12 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
|
||||
context = kgsl_context_get(device, curr_context_id);
|
||||
if (context != NULL) {
|
||||
curr_context = context->devctxt;
|
||||
struct task_struct *task;
|
||||
curr_context = ADRENO_CONTEXT(context);
|
||||
curr_context->ib_gpu_time_used = 0;
|
||||
task = find_task_by_vpid(context->pid);
|
||||
if (task)
|
||||
get_task_comm(pid_name, task);
|
||||
} else {
|
||||
KGSL_DRV_ERR(device,
|
||||
"Fault tolerance no context found\n");
|
||||
@@ -3499,8 +3507,7 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
KGSL_FT_ERR(device,
|
||||
"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
|
||||
" on global ts %d\n",
|
||||
curr_context ? curr_context->pid_name : "",
|
||||
curr_context ? curr_context->id : 0,
|
||||
pid_name, context ? context->id : 0,
|
||||
(kgsl_readtimestamp(device, context,
|
||||
KGSL_TIMESTAMP_RETIRED) + 1),
|
||||
curr_global_ts + 1);
|
||||
@@ -3512,7 +3519,7 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
|
||||
KGSL_FT_INFO(device,
|
||||
"Proc %s used GPU Time %d ms on timestamp 0x%X\n",
|
||||
curr_context->pid_name, curr_context->ib_gpu_time_used,
|
||||
pid_name, curr_context->ib_gpu_time_used,
|
||||
curr_global_ts+1);
|
||||
|
||||
if ((long_ib_detected) &&
|
||||
@@ -3528,8 +3535,7 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
"Proc %s, ctxt_id %d ts %d"
|
||||
"used GPU for %d ms long ib "
|
||||
"detected on global ts %d\n",
|
||||
curr_context->pid_name,
|
||||
curr_context->id,
|
||||
pid_name, context->id,
|
||||
(kgsl_readtimestamp(device,
|
||||
context,
|
||||
KGSL_TIMESTAMP_RETIRED)+1),
|
||||
@@ -3551,6 +3557,7 @@ unsigned int adreno_ft_detect(struct kgsl_device *device,
|
||||
kgsl_context_put(context);
|
||||
context = NULL;
|
||||
curr_context = NULL;
|
||||
strlcpy(pid_name, "unknown", sizeof(pid_name));
|
||||
adreno_dev->long_ib = 0;
|
||||
adreno_dev->long_ib_ts = 0;
|
||||
}
|
||||
@@ -3608,7 +3615,8 @@ static int adreno_waittimestamp(struct kgsl_device *device,
|
||||
unsigned int msecs)
|
||||
{
|
||||
static unsigned int io_cnt;
|
||||
struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
|
||||
struct adreno_context *adreno_ctx = context ? ADRENO_CONTEXT(context) :
|
||||
NULL;
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
unsigned int context_id = _get_context_id(context);
|
||||
unsigned int time_elapsed = 0;
|
||||
@@ -3929,6 +3937,7 @@ static const struct kgsl_functable adreno_functable = {
|
||||
/* Optional functions */
|
||||
.setstate = adreno_setstate,
|
||||
.drawctxt_create = adreno_drawctxt_create,
|
||||
.drawctxt_detach = adreno_drawctxt_detach,
|
||||
.drawctxt_destroy = adreno_drawctxt_destroy,
|
||||
.setproperty = adreno_setproperty,
|
||||
.postmortem_dump = adreno_dump,
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#define ADRENO_DEVICE(device) \
|
||||
KGSL_CONTAINER_OF(device, struct adreno_device, dev)
|
||||
|
||||
#define ADRENO_CONTEXT(device) \
|
||||
KGSL_CONTAINER_OF(device, struct adreno_context, base)
|
||||
|
||||
#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
|
||||
#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
|
||||
#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
|
||||
|
||||
@@ -1355,7 +1355,7 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
tmp_ctx.gmem_base = adreno_dev->gmem_base;
|
||||
|
||||
result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
|
||||
drawctxt->pagetable, drawctxt->context_gmem_shadow.size);
|
||||
drawctxt->base.pagetable, drawctxt->context_gmem_shadow.size);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
@@ -1364,7 +1364,7 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
|
||||
|
||||
/* blank out gmem shadow. */
|
||||
kgsl_sharedmem_set(drawctxt->dev_priv->device,
|
||||
kgsl_sharedmem_set(drawctxt->base.device,
|
||||
&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
|
||||
drawctxt->context_gmem_shadow.size);
|
||||
|
||||
@@ -1389,7 +1389,7 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
|
||||
KGSL_CACHE_OP_FLUSH);
|
||||
|
||||
kgsl_cffdump_syncmem(drawctxt->dev_priv,
|
||||
kgsl_cffdump_syncmem(drawctxt->base.device,
|
||||
&drawctxt->context_gmem_shadow.gmemshadow,
|
||||
drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
|
||||
drawctxt->context_gmem_shadow.gmemshadow.size, false);
|
||||
@@ -1410,13 +1410,13 @@ static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
|
||||
*/
|
||||
|
||||
ret = kgsl_allocate(&drawctxt->gpustate,
|
||||
drawctxt->pagetable, _context_size(adreno_dev));
|
||||
drawctxt->base.pagetable, _context_size(adreno_dev));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
kgsl_sharedmem_set(drawctxt->dev_priv->device, &drawctxt->gpustate, 0,
|
||||
0, _context_size(adreno_dev));
|
||||
kgsl_sharedmem_set(drawctxt->base.device, &drawctxt->gpustate,
|
||||
0, 0, _context_size(adreno_dev));
|
||||
|
||||
tmp_ctx.cmd = tmp_ctx.start
|
||||
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
|
||||
@@ -1440,8 +1440,8 @@ static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
|
||||
kgsl_cache_range_op(&drawctxt->gpustate,
|
||||
KGSL_CACHE_OP_FLUSH);
|
||||
|
||||
kgsl_cffdump_syncmem(drawctxt->dev_priv, &drawctxt->gpustate,
|
||||
drawctxt->gpustate.gpuaddr,
|
||||
kgsl_cffdump_syncmem(drawctxt->base.device,
|
||||
&drawctxt->gpustate, drawctxt->gpustate.gpuaddr,
|
||||
drawctxt->gpustate.size, false);
|
||||
|
||||
done:
|
||||
@@ -1516,7 +1516,7 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
"Current active context has caused gpu hang\n");
|
||||
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
|
||||
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
|
||||
context->reg_save[1],
|
||||
context->reg_save[2] << 2, true);
|
||||
/* save registers and constants. */
|
||||
@@ -1525,7 +1525,7 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
context->reg_save, 3);
|
||||
|
||||
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->shader_save[1],
|
||||
context->shader_save[2] << 2, true);
|
||||
@@ -1534,7 +1534,7 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
KGSL_CMD_FLAGS_PMODE,
|
||||
context->shader_save, 3);
|
||||
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->shader_fixup[1],
|
||||
context->shader_fixup[2] << 2, true);
|
||||
@@ -1552,7 +1552,7 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
|
||||
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
|
||||
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
|
||||
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
|
||||
context->context_gmem_shadow.gmem_save[1],
|
||||
context->context_gmem_shadow.gmem_save[2] << 2, true);
|
||||
/* save gmem.
|
||||
@@ -1562,7 +1562,7 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
KGSL_CMD_FLAGS_PMODE,
|
||||
context->context_gmem_shadow.gmem_save, 3);
|
||||
|
||||
kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
|
||||
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
|
||||
context->chicken_restore[1],
|
||||
context->chicken_restore[2] << 2, true);
|
||||
|
||||
@@ -1586,9 +1586,18 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
unsigned int cmds[5];
|
||||
|
||||
if (context == NULL) {
|
||||
/* No context - set the default apgetable and thats it */
|
||||
/* No context - set the default pagetable and thats it */
|
||||
unsigned int id;
|
||||
/*
|
||||
* If there isn't a current context, the kgsl_mmu_setstate
|
||||
* will use the CPU path so we don't need to give
|
||||
* it a valid context id.
|
||||
*/
|
||||
id = (adreno_dev->drawctxt_active != NULL)
|
||||
? adreno_dev->drawctxt_active->base.id
|
||||
: KGSL_CONTEXT_INVALID;
|
||||
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
|
||||
adreno_dev->drawctxt_active->id);
|
||||
id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1597,16 +1606,17 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
|
||||
cmds[3] = device->memstore.gpuaddr +
|
||||
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
|
||||
cmds[4] = context->id;
|
||||
cmds[4] = context->base.id;
|
||||
adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
|
||||
cmds, 5);
|
||||
kgsl_mmu_setstate(&device->mmu, context->pagetable, context->id);
|
||||
kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
|
||||
context->base.id);
|
||||
|
||||
/* restore gmem.
|
||||
* (note: changes shader. shader must not already be restored.)
|
||||
*/
|
||||
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
|
||||
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
|
||||
context->context_gmem_shadow.gmem_restore[1],
|
||||
context->context_gmem_shadow.gmem_restore[2] << 2,
|
||||
true);
|
||||
@@ -1616,7 +1626,7 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
context->context_gmem_shadow.gmem_restore, 3);
|
||||
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->chicken_restore[1],
|
||||
context->chicken_restore[2] << 2, true);
|
||||
@@ -1631,7 +1641,7 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
}
|
||||
|
||||
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
|
||||
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
|
||||
context->reg_restore[1],
|
||||
context->reg_restore[2] << 2, true);
|
||||
|
||||
@@ -1641,7 +1651,7 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
|
||||
/* restore shader instructions & partitioning. */
|
||||
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->shader_restore[1],
|
||||
context->shader_restore[2] << 2, true);
|
||||
|
||||
@@ -2321,7 +2321,7 @@ static int a3xx_create_gmem_shadow(struct adreno_device *adreno_dev,
|
||||
tmp_ctx.gmem_base = adreno_dev->gmem_base;
|
||||
|
||||
result = kgsl_allocate(&drawctxt->context_gmem_shadow.gmemshadow,
|
||||
drawctxt->pagetable, drawctxt->context_gmem_shadow.size);
|
||||
drawctxt->base.pagetable, drawctxt->context_gmem_shadow.size);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
@@ -2355,7 +2355,7 @@ static int a3xx_drawctxt_create(struct adreno_device *adreno_dev,
|
||||
*/
|
||||
|
||||
ret = kgsl_allocate(&drawctxt->gpustate,
|
||||
drawctxt->pagetable, CONTEXT_SIZE);
|
||||
drawctxt->base.pagetable, CONTEXT_SIZE);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -2420,7 +2420,7 @@ static void a3xx_drawctxt_save(struct adreno_device *adreno_dev,
|
||||
* already be saved.)
|
||||
*/
|
||||
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->context_gmem_shadow.gmem_save[1],
|
||||
context->context_gmem_shadow.gmem_save[2] << 2, true);
|
||||
@@ -2441,8 +2441,17 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
|
||||
if (context == NULL) {
|
||||
/* No context - set the default pagetable and thats it */
|
||||
unsigned int id;
|
||||
/*
|
||||
* If there isn't a current context, the kgsl_mmu_setstate
|
||||
* will use the CPU path so we don't need to give
|
||||
* it a valid context id.
|
||||
*/
|
||||
id = (adreno_dev->drawctxt_active != NULL)
|
||||
? adreno_dev->drawctxt_active->base.id
|
||||
: KGSL_CONTEXT_INVALID;
|
||||
kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
|
||||
adreno_dev->drawctxt_active->id);
|
||||
id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2451,10 +2460,11 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2);
|
||||
cmds[3] = device->memstore.gpuaddr +
|
||||
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
|
||||
cmds[4] = context->id;
|
||||
cmds[4] = context->base.id;
|
||||
adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
|
||||
cmds, 5);
|
||||
kgsl_mmu_setstate(&device->mmu, context->pagetable, context->id);
|
||||
kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
|
||||
context->base.id);
|
||||
|
||||
/*
|
||||
* Restore GMEM. (note: changes shader.
|
||||
@@ -2462,7 +2472,7 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
|
||||
*/
|
||||
|
||||
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
|
||||
kgsl_cffdump_syncmem(context->dev_priv,
|
||||
kgsl_cffdump_syncmem(context->base.device,
|
||||
&context->gpustate,
|
||||
context->context_gmem_shadow.gmem_restore[1],
|
||||
context->context_gmem_shadow.gmem_restore[2] << 2,
|
||||
|
||||
@@ -134,34 +134,33 @@ void build_quad_vtxbuff(struct adreno_context *drawctxt,
|
||||
|
||||
/**
|
||||
* adreno_drawctxt_create - create a new adreno draw context
|
||||
* @device - KGSL device to create the context on
|
||||
* @pagetable - Pagetable for the context
|
||||
* @context- Generic KGSL context structure
|
||||
* @flags - flags for the context (passed from user space)
|
||||
* @dev_priv: the owner of the context
|
||||
* @flags: flags for the context (passed from user space)
|
||||
*
|
||||
* Create a new draw context for the 3D core. Return 0 on success,
|
||||
* or error code on failure.
|
||||
* Create and return a new draw context for the 3D core.
|
||||
*/
|
||||
int adreno_drawctxt_create(struct kgsl_device *device,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
struct kgsl_context *context, uint32_t *flags)
|
||||
struct kgsl_context *
|
||||
adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
|
||||
uint32_t *flags)
|
||||
{
|
||||
struct adreno_context *drawctxt;
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
|
||||
int ret;
|
||||
|
||||
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
|
||||
|
||||
if (drawctxt == NULL)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = kgsl_context_init(dev_priv, &drawctxt->base);
|
||||
if (ret != 0) {
|
||||
kfree(drawctxt);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
drawctxt->pid = task_pid_nr(current);
|
||||
strlcpy(drawctxt->pid_name, current->comm, TASK_COMM_LEN);
|
||||
drawctxt->pagetable = pagetable;
|
||||
drawctxt->bin_base_offset = 0;
|
||||
drawctxt->id = context->id;
|
||||
rb->timestamp[context->id] = 0;
|
||||
rb->timestamp[drawctxt->base.id] = 0;
|
||||
|
||||
*flags &= (KGSL_CONTEXT_PREAMBLE |
|
||||
KGSL_CONTEXT_NO_GMEM_ALLOC |
|
||||
@@ -192,50 +191,47 @@ int adreno_drawctxt_create(struct kgsl_device *device,
|
||||
|
||||
drawctxt->type =
|
||||
(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
|
||||
drawctxt->dev_priv = context->dev_priv;
|
||||
|
||||
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
kgsl_sharedmem_writel(device, &device->memstore,
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
|
||||
KGSL_INIT_REFTIMESTAMP);
|
||||
kgsl_sharedmem_writel(device, &device->memstore,
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
|
||||
0);
|
||||
kgsl_sharedmem_writel(device, &device->memstore,
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
|
||||
0);
|
||||
kgsl_sharedmem_writel(device, &device->memstore,
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
|
||||
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
|
||||
0);
|
||||
|
||||
context->devctxt = drawctxt;
|
||||
return 0;
|
||||
return &drawctxt->base;
|
||||
err:
|
||||
kfree(drawctxt);
|
||||
return ret;
|
||||
kgsl_context_put(&drawctxt->base);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* adreno_drawctxt_destroy - destroy a draw context
|
||||
* @device - KGSL device that owns the context
|
||||
* @context- Generic KGSL context container for the context
|
||||
* adreno_drawctxt_detach(): detach a context from the GPU
|
||||
* @context: Generic KGSL context container for the context
|
||||
*
|
||||
* Destroy an existing context. Return 0 on success or error
|
||||
* code on failure.
|
||||
*/
|
||||
|
||||
/* destroy a drawing context */
|
||||
|
||||
void adreno_drawctxt_destroy(struct kgsl_device *device,
|
||||
struct kgsl_context *context)
|
||||
void adreno_drawctxt_detach(struct kgsl_context *context)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct kgsl_device *device;
|
||||
struct adreno_device *adreno_dev;
|
||||
struct adreno_context *drawctxt;
|
||||
|
||||
if (context == NULL || context->devctxt == NULL)
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
drawctxt = context->devctxt;
|
||||
device = context->device;
|
||||
adreno_dev = ADRENO_DEVICE(device);
|
||||
drawctxt = ADRENO_CONTEXT(context);
|
||||
/* deactivate context */
|
||||
if (adreno_dev->drawctxt_active == drawctxt) {
|
||||
/* no need to save GMEM or shader, the context is
|
||||
@@ -256,9 +252,17 @@ void adreno_drawctxt_destroy(struct kgsl_device *device,
|
||||
|
||||
kgsl_sharedmem_free(&drawctxt->gpustate);
|
||||
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
|
||||
}
|
||||
|
||||
|
||||
void adreno_drawctxt_destroy(struct kgsl_context *context)
|
||||
{
|
||||
struct adreno_context *drawctxt;
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
drawctxt = ADRENO_CONTEXT(context);
|
||||
kfree(drawctxt);
|
||||
context->devctxt = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,10 +278,12 @@ void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
|
||||
struct kgsl_context *context,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct adreno_context *drawctxt = context->devctxt;
|
||||
struct adreno_context *drawctxt;
|
||||
|
||||
if (drawctxt)
|
||||
drawctxt->bin_base_offset = offset;
|
||||
if (context == NULL)
|
||||
return;
|
||||
drawctxt = ADRENO_CONTEXT(context);
|
||||
drawctxt->bin_base_offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,8 +322,8 @@ void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
||||
|
||||
KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
|
||||
adreno_dev->drawctxt_active ?
|
||||
adreno_dev->drawctxt_active->id : 0,
|
||||
drawctxt ? drawctxt->id : 0, flags);
|
||||
adreno_dev->drawctxt_active->base.id : 0,
|
||||
drawctxt ? drawctxt->base.id : 0, flags);
|
||||
|
||||
/* Save the old context */
|
||||
adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
#ifndef __ADRENO_DRAWCTXT_H
|
||||
#define __ADRENO_DRAWCTXT_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "adreno_pm4types.h"
|
||||
#include "a2xx_reg.h"
|
||||
|
||||
@@ -96,15 +94,10 @@ struct gmem_shadow_t {
|
||||
};
|
||||
|
||||
struct adreno_context {
|
||||
pid_t pid;
|
||||
char pid_name[TASK_COMM_LEN];
|
||||
unsigned int id;
|
||||
struct kgsl_context base;
|
||||
unsigned int ib_gpu_time_used;
|
||||
uint32_t flags;
|
||||
uint32_t pagefault;
|
||||
unsigned long pagefault_ts;
|
||||
unsigned int type;
|
||||
struct kgsl_pagetable *pagetable;
|
||||
struct kgsl_memdesc gpustate;
|
||||
unsigned int reg_restore[3];
|
||||
unsigned int shader_save[3];
|
||||
@@ -131,16 +124,15 @@ struct adreno_context {
|
||||
struct kgsl_memdesc constant_load_commands[3];
|
||||
struct kgsl_memdesc cond_execs[4];
|
||||
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
|
||||
struct kgsl_device_private *dev_priv;
|
||||
};
|
||||
|
||||
int adreno_drawctxt_create(struct kgsl_device *device,
|
||||
struct kgsl_pagetable *pagetable,
|
||||
struct kgsl_context *context,
|
||||
|
||||
struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
|
||||
uint32_t *flags);
|
||||
|
||||
void adreno_drawctxt_destroy(struct kgsl_device *device,
|
||||
struct kgsl_context *context);
|
||||
void adreno_drawctxt_detach(struct kgsl_context *context);
|
||||
|
||||
void adreno_drawctxt_destroy(struct kgsl_context *context);
|
||||
|
||||
void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt,
|
||||
|
||||
@@ -138,7 +138,7 @@ err:
|
||||
if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
|
||||
KGSL_CTXT_WARN(rb->device,
|
||||
"Context %p caused a gpu hang. Will not accept commands for context %d\n",
|
||||
context, context->id);
|
||||
context, context->base.id);
|
||||
return -EDEADLK;
|
||||
}
|
||||
wait_time = jiffies + wait_timeout;
|
||||
@@ -616,7 +616,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
|
||||
*/
|
||||
if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
|
||||
!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
|
||||
context_id = context->id;
|
||||
context_id = context->base.id;
|
||||
|
||||
if ((context && (context->flags & CTXT_FLAGS_USER_GENERATED_TS)) &&
|
||||
!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
|
||||
@@ -1097,12 +1097,9 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
drawctxt = context->devctxt;
|
||||
drawctxt = ADRENO_CONTEXT(context);
|
||||
|
||||
if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
|
||||
KGSL_CTXT_ERR(device, "proc %s failed fault tolerance"
|
||||
" will not accept commands for context %d\n",
|
||||
drawctxt->pid_name, drawctxt->id);
|
||||
ret = -EDEADLK;
|
||||
goto done;
|
||||
}
|
||||
@@ -1116,10 +1113,6 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
start_index = 1;
|
||||
|
||||
if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
|
||||
KGSL_CTXT_ERR(device,
|
||||
"proc %s triggered fault tolerance"
|
||||
" skipping commands for context till EOF %d\n",
|
||||
drawctxt->pid_name, drawctxt->id);
|
||||
if (flags & KGSL_CMD_FLAGS_EOF)
|
||||
drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
|
||||
if (start_index)
|
||||
@@ -1282,7 +1275,7 @@ void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
k_ctxt = kgsl_context_get(device, ft_data->context_id);
|
||||
|
||||
if (k_ctxt) {
|
||||
a_ctxt = k_ctxt->devctxt;
|
||||
a_ctxt = ADRENO_CONTEXT(k_ctxt);
|
||||
if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
|
||||
_turn_preamble_on_for_ib_seq(rb, rb_rptr);
|
||||
kgsl_context_put(k_ctxt);
|
||||
@@ -1319,7 +1312,7 @@ void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
k_ctxt = kgsl_context_get(rb->device, val2);
|
||||
|
||||
if (k_ctxt) {
|
||||
a_ctxt = k_ctxt->devctxt;
|
||||
a_ctxt = ADRENO_CONTEXT(k_ctxt);
|
||||
|
||||
/* If we are changing to a good context and were not
|
||||
* copying commands then copy over commands to the good
|
||||
|
||||
+64
-65
@@ -448,20 +448,24 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
|
||||
entry->priv = NULL;
|
||||
}
|
||||
|
||||
/* Allocate a new context id */
|
||||
|
||||
static struct kgsl_context *
|
||||
kgsl_create_context(struct kgsl_device_private *dev_priv)
|
||||
/**
|
||||
* kgsl_context_init() - helper to initialize kgsl_context members
|
||||
* @dev_priv: the owner of the context
|
||||
* @context: the newly created context struct, should be allocated by
|
||||
* the device specific drawctxt_create function.
|
||||
*
|
||||
* This is a helper function for the device specific drawctxt_create
|
||||
* function to initialize the common members of its context struct.
|
||||
* If this function succeeds, reference counting is active in the context
|
||||
* struct and the caller should kgsl_context_put() it on error.
|
||||
* If it fails, the caller should just free the context structure
|
||||
* it passed in.
|
||||
*/
|
||||
int kgsl_context_init(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_context *context)
|
||||
{
|
||||
int ret = 0, id;
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
struct kgsl_context *context;
|
||||
int ret, id = 0;
|
||||
|
||||
context = kzalloc(sizeof(*context), GFP_KERNEL);
|
||||
|
||||
if (context == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
||||
while (1) {
|
||||
if (idr_pre_get(&device->context_idr, GFP_KERNEL) == 0) {
|
||||
@@ -480,30 +484,26 @@ kgsl_create_context(struct kgsl_device_private *dev_priv)
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto func_end;
|
||||
goto fail;
|
||||
|
||||
/* MAX - 1, there is one memdesc in memstore for device info */
|
||||
if (id >= KGSL_MEMSTORE_MAX) {
|
||||
KGSL_DRV_INFO(device, "cannot have more than %d "
|
||||
"ctxts due to memstore limitation\n",
|
||||
KGSL_MEMSTORE_MAX);
|
||||
write_lock(&device->context_lock);
|
||||
idr_remove(&device->context_idr, id);
|
||||
write_unlock(&device->context_lock);
|
||||
ret = -ENOSPC;
|
||||
goto func_end;
|
||||
goto fail_free_id;
|
||||
}
|
||||
|
||||
kref_init(&context->refcount);
|
||||
context->dev_priv = dev_priv;
|
||||
context->device = dev_priv->device;
|
||||
context->pagetable = dev_priv->process_priv->pagetable;
|
||||
|
||||
context->pid = dev_priv->process_priv->pid;
|
||||
|
||||
ret = kgsl_sync_timeline_create(context);
|
||||
if (ret) {
|
||||
write_lock(&device->context_lock);
|
||||
idr_remove(&dev_priv->device->context_idr, id);
|
||||
write_unlock(&device->context_lock);
|
||||
goto func_end;
|
||||
}
|
||||
if (ret)
|
||||
goto fail_free_id;
|
||||
|
||||
/* Initialize the pending event list */
|
||||
INIT_LIST_HEAD(&context->events);
|
||||
@@ -518,15 +518,15 @@ kgsl_create_context(struct kgsl_device_private *dev_priv)
|
||||
*/
|
||||
|
||||
INIT_LIST_HEAD(&context->events_list);
|
||||
|
||||
func_end:
|
||||
if (ret) {
|
||||
kfree(context);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return context;
|
||||
return 0;
|
||||
fail_free_id:
|
||||
write_lock(&device->context_lock);
|
||||
idr_remove(&dev_priv->device->context_idr, id);
|
||||
write_unlock(&device->context_lock);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_context_init);
|
||||
|
||||
/**
|
||||
* kgsl_context_detach - Release the "master" context reference
|
||||
@@ -536,37 +536,36 @@ func_end:
|
||||
* has requested for it to be destroyed. The context itself may
|
||||
* exist a bit longer until its reference count goes to zero.
|
||||
* Other code referencing the context can detect that it has been
|
||||
* detached because the context id will be set to KGSL_CONTEXT_INVALID.
|
||||
* detached by checking the KGSL_CONTEXT_DETACHED bit in
|
||||
* context->priv.
|
||||
*/
|
||||
void
|
||||
kgsl_context_detach(struct kgsl_context *context)
|
||||
{
|
||||
int id;
|
||||
struct kgsl_device *device;
|
||||
if (context == NULL)
|
||||
return;
|
||||
device = context->dev_priv->device;
|
||||
trace_kgsl_context_detach(device, context);
|
||||
id = context->id;
|
||||
|
||||
if (device->ftbl->drawctxt_destroy)
|
||||
device->ftbl->drawctxt_destroy(device, context);
|
||||
/*device specific drawctxt_destroy MUST clean up devctxt */
|
||||
BUG_ON(context->devctxt);
|
||||
device = context->device;
|
||||
|
||||
/*
|
||||
* Mark the context as detached to keep others from using
|
||||
* the context before it gets fully removed, and to make sure
|
||||
* we don't try to detach twice.
|
||||
*/
|
||||
if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
|
||||
return;
|
||||
|
||||
trace_kgsl_context_detach(device, context);
|
||||
|
||||
device->ftbl->drawctxt_detach(context);
|
||||
/*
|
||||
* Cancel events after the device-specific context is
|
||||
* destroyed, to avoid possibly freeing memory while
|
||||
* detached, to avoid possibly freeing memory while
|
||||
* it is still in use by the GPU.
|
||||
*/
|
||||
kgsl_cancel_events_ctxt(device, context);
|
||||
|
||||
write_lock(&device->context_lock);
|
||||
context->id = KGSL_CONTEXT_INVALID;
|
||||
idr_remove(&device->context_idr, id);
|
||||
write_unlock(&device->context_lock);
|
||||
|
||||
context->dev_priv = NULL;
|
||||
|
||||
kgsl_context_put(context);
|
||||
}
|
||||
|
||||
@@ -575,8 +574,19 @@ kgsl_context_destroy(struct kref *kref)
|
||||
{
|
||||
struct kgsl_context *context = container_of(kref, struct kgsl_context,
|
||||
refcount);
|
||||
struct kgsl_device *device = context->device;
|
||||
|
||||
trace_kgsl_context_destroy(device, context);
|
||||
|
||||
write_lock(&device->context_lock);
|
||||
if (context->id != KGSL_CONTEXT_INVALID) {
|
||||
idr_remove(&device->context_idr, context->id);
|
||||
context->id = KGSL_CONTEXT_INVALID;
|
||||
}
|
||||
write_unlock(&device->context_lock);
|
||||
kgsl_sync_timeline_destroy(context);
|
||||
kfree(context);
|
||||
|
||||
device->ftbl->drawctxt_destroy(context);
|
||||
}
|
||||
|
||||
struct kgsl_device *kgsl_get_device(int dev_idx)
|
||||
@@ -975,7 +985,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
|
||||
if (context == NULL)
|
||||
break;
|
||||
|
||||
if (context->dev_priv == dev_priv)
|
||||
if (context->pid == private->pid)
|
||||
kgsl_context_detach(context);
|
||||
|
||||
next = next + 1;
|
||||
@@ -1623,27 +1633,16 @@ static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
|
||||
int result = 0;
|
||||
struct kgsl_drawctxt_create *param = data;
|
||||
struct kgsl_context *context = NULL;
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
|
||||
context = kgsl_create_context(dev_priv);
|
||||
|
||||
context = device->ftbl->drawctxt_create(dev_priv, ¶m->flags);
|
||||
if (IS_ERR(context)) {
|
||||
result = PTR_ERR(context);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (dev_priv->device->ftbl->drawctxt_create) {
|
||||
result = dev_priv->device->ftbl->drawctxt_create(
|
||||
dev_priv->device, dev_priv->process_priv->pagetable,
|
||||
context, ¶m->flags);
|
||||
if (result)
|
||||
goto done;
|
||||
}
|
||||
trace_kgsl_context_create(dev_priv->device, context, param->flags);
|
||||
param->drawctxt_id = context->id;
|
||||
done:
|
||||
if (result && !IS_ERR(context))
|
||||
kgsl_context_detach(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2600,7 +2599,7 @@ static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
|
||||
if (!entry)
|
||||
return -EINVAL;
|
||||
|
||||
kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
|
||||
kgsl_cffdump_syncmem(dev_priv->device, &entry->memdesc, param->gpuaddr,
|
||||
param->len, true);
|
||||
|
||||
kgsl_mem_entry_put(entry);
|
||||
|
||||
@@ -410,29 +410,19 @@ void kgsl_cffdump_user_event(struct kgsl_device *device,
|
||||
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
|
||||
}
|
||||
|
||||
void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes,
|
||||
bool clean_cache)
|
||||
void kgsl_cffdump_syncmem(struct kgsl_device *device,
|
||||
struct kgsl_memdesc *memdesc, uint gpuaddr,
|
||||
uint sizebytes, bool clean_cache)
|
||||
{
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
const void *src;
|
||||
|
||||
if (!device->cff_dump_enable)
|
||||
return;
|
||||
|
||||
BUG_ON(memdesc == NULL);
|
||||
|
||||
total_syncmem += sizebytes;
|
||||
|
||||
if (memdesc == NULL) {
|
||||
struct kgsl_mem_entry *entry;
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
gpuaddr, sizebytes);
|
||||
if (entry == NULL) {
|
||||
KGSL_CORE_ERR("did not find mapping "
|
||||
"for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return;
|
||||
}
|
||||
memdesc = &entry->memdesc;
|
||||
}
|
||||
src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
|
||||
if (memdesc->hostptr == NULL) {
|
||||
KGSL_CORE_ERR(
|
||||
|
||||
@@ -28,7 +28,7 @@ void kgsl_cffdump_init(void);
|
||||
void kgsl_cffdump_destroy(void);
|
||||
void kgsl_cffdump_open(struct kgsl_device *device);
|
||||
void kgsl_cffdump_close(struct kgsl_device *device);
|
||||
void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
void kgsl_cffdump_syncmem(struct kgsl_device *,
|
||||
struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
|
||||
bool clean_cache);
|
||||
void kgsl_cffdump_setmem(struct kgsl_device *device, uint addr,
|
||||
@@ -74,7 +74,7 @@ static inline void kgsl_cffdump_close(struct kgsl_device *device)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
|
||||
static inline void kgsl_cffdump_syncmem(struct kgsl_device *device,
|
||||
struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
|
||||
bool clean_cache)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <linux/idr.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_mmu.h"
|
||||
@@ -103,11 +104,10 @@ struct kgsl_functable {
|
||||
calling the hook */
|
||||
void (*setstate) (struct kgsl_device *device, unsigned int context_id,
|
||||
uint32_t flags);
|
||||
int (*drawctxt_create) (struct kgsl_device *device,
|
||||
struct kgsl_pagetable *pagetable, struct kgsl_context *context,
|
||||
uint32_t *flags);
|
||||
void (*drawctxt_destroy) (struct kgsl_device *device,
|
||||
struct kgsl_context *context);
|
||||
struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *,
|
||||
uint32_t *flags);
|
||||
void (*drawctxt_detach) (struct kgsl_context *context);
|
||||
void (*drawctxt_destroy) (struct kgsl_context *context);
|
||||
long (*ioctl) (struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data);
|
||||
int (*setproperty) (struct kgsl_device *device,
|
||||
@@ -254,31 +254,44 @@ void kgsl_process_events(struct work_struct *work);
|
||||
.ver_minor = DRIVER_VERSION_MINOR
|
||||
|
||||
|
||||
/* bits for struct kgsl_context.priv */
|
||||
/* the context has been destroyed by userspace and is no longer using the gpu */
|
||||
#define KGSL_CONTEXT_DETACHED 0
|
||||
/* the context has caused a pagefault */
|
||||
#define KGSL_CONTEXT_PAGEFAULT 1
|
||||
|
||||
/**
|
||||
* struct kgsl_context - Master structure for a KGSL context object
|
||||
* @refcount - kref object for reference counting the context
|
||||
* @id - integer identifier for the context
|
||||
* @dev_priv - pointer to the owning device instance
|
||||
* @devctxt - pointer to the device specific context information
|
||||
* @reset_status - status indication whether a gpu reset occured and whether
|
||||
* @refcount: kref object for reference counting the context
|
||||
* @id: integer identifier for the context
|
||||
* @priv: in-kernel context flags, use KGSL_CONTEXT_* values
|
||||
* @dev_priv: pointer to the owning device instance
|
||||
* @reset_status: status indication whether a gpu reset occured and whether
|
||||
* this context was responsible for causing it
|
||||
* @wait_on_invalid_ts - flag indicating if this context has tried to wait on a
|
||||
* @wait_on_invalid_ts: flag indicating if this context has tried to wait on a
|
||||
* bad timestamp
|
||||
* @timeline - sync timeline used to create fences that can be signaled when a
|
||||
* @timeline: sync timeline used to create fences that can be signaled when a
|
||||
* sync_pt timestamp expires
|
||||
* @events - list head of pending events for this context
|
||||
* @events_list - list node for the list of all contexts that have pending events
|
||||
* @events: list head of pending events for this context
|
||||
* @events_list: list node for the list of all contexts that have pending events
|
||||
* @pid: process that owns this context.
|
||||
* @pagefault: flag set if this context caused a pagefault.
|
||||
* @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT
|
||||
* is set.
|
||||
*/
|
||||
struct kgsl_context {
|
||||
struct kref refcount;
|
||||
uint32_t id;
|
||||
struct kgsl_device_private *dev_priv;
|
||||
void *devctxt;
|
||||
pid_t pid;
|
||||
unsigned long priv;
|
||||
struct kgsl_device *device;
|
||||
struct kgsl_pagetable *pagetable;
|
||||
unsigned int reset_status;
|
||||
bool wait_on_invalid_ts;
|
||||
struct sync_timeline *timeline;
|
||||
struct list_head events;
|
||||
struct list_head events_list;
|
||||
unsigned int pagefault_ts;
|
||||
};
|
||||
|
||||
struct kgsl_process_private {
|
||||
@@ -429,6 +442,9 @@ kgsl_device_get_drvdata(struct kgsl_device *dev)
|
||||
|
||||
void kgsl_context_destroy(struct kref *kref);
|
||||
|
||||
int kgsl_context_init(struct kgsl_device_private *, struct kgsl_context
|
||||
*context);
|
||||
|
||||
/**
|
||||
* kgsl_context_put() - Release context reference count
|
||||
* @context: Pointer to the KGSL context to be released
|
||||
@@ -442,6 +458,22 @@ kgsl_context_put(struct kgsl_context *context)
|
||||
if (context)
|
||||
kref_put(&context->refcount, kgsl_context_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_context_detached() - check if a context is detached
|
||||
* @context: the context
|
||||
*
|
||||
* Check if a context has been destroyed by userspace and is only waiting
|
||||
* for reference counts to go away. This check is used to weed out
|
||||
* contexts that shouldn't use the gpu so NULL is considered detached.
|
||||
*/
|
||||
static inline bool kgsl_context_detached(struct kgsl_context *context)
|
||||
{
|
||||
return (context == NULL || test_bit(KGSL_CONTEXT_DETACHED,
|
||||
&context->priv));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kgsl_context_get() - get a pointer to a KGSL context
|
||||
* @device: Pointer to the KGSL device that owns the context
|
||||
@@ -462,7 +494,10 @@ static inline struct kgsl_context *kgsl_context_get(struct kgsl_device *device,
|
||||
|
||||
context = idr_find(&device->context_idr, id);
|
||||
|
||||
if (context)
|
||||
/* Don't return a context that has been detached */
|
||||
if (kgsl_context_detached(context))
|
||||
context = NULL;
|
||||
else
|
||||
kref_get(&context->refcount);
|
||||
|
||||
read_unlock(&device->context_lock);
|
||||
@@ -489,8 +524,8 @@ static inline struct kgsl_context *kgsl_context_get_owner(
|
||||
|
||||
context = kgsl_context_get(dev_priv->device, id);
|
||||
|
||||
/* Verify that the context belongs to the dev_priv instance */
|
||||
if (context && context->dev_priv != dev_priv) {
|
||||
/* Verify that the context belongs to current calling process. */
|
||||
if (context != NULL && context->pid != dev_priv->process_priv->pid) {
|
||||
kgsl_context_put(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
|
||||
unsigned int no_page_fault_log = 0;
|
||||
unsigned int curr_context_id = 0;
|
||||
unsigned int curr_global_ts = 0;
|
||||
static struct kgsl_context *context;
|
||||
struct kgsl_context *context;
|
||||
|
||||
ret = get_iommu_unit(dev, &mmu, &iommu_unit);
|
||||
if (ret)
|
||||
@@ -401,23 +401,16 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
|
||||
context = kgsl_context_get(device, curr_context_id);
|
||||
|
||||
if (context != NULL) {
|
||||
struct adreno_context *drawctxt = context->devctxt;
|
||||
|
||||
kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
|
||||
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
|
||||
eoptimestamp));
|
||||
|
||||
/*
|
||||
* Store pagefault's timestamp in adreno context,
|
||||
* this information will be used in GFT
|
||||
*/
|
||||
|
||||
if (drawctxt != NULL) {
|
||||
drawctxt->pagefault = 1;
|
||||
drawctxt->pagefault_ts = curr_global_ts;
|
||||
}
|
||||
/* save pagefault timestamp for GFT */
|
||||
set_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
|
||||
context->pagefault_ts = curr_global_ts;
|
||||
|
||||
kgsl_context_put(context);
|
||||
context = NULL;
|
||||
}
|
||||
|
||||
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
|
||||
|
||||
@@ -109,7 +109,7 @@ static int snapshot_context_info(int id, void *ptr, void *data)
|
||||
struct kgsl_device *device;
|
||||
|
||||
if (context)
|
||||
device = context->dev_priv->device;
|
||||
device = context->device;
|
||||
else
|
||||
device = (struct kgsl_device *)data;
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ int kgsl_sync_timeline_create(struct kgsl_context *context)
|
||||
char ktimeline_name[sizeof(context->timeline->name)] = {};
|
||||
snprintf(ktimeline_name, sizeof(ktimeline_name),
|
||||
"%s_%.15s(%d)-%.15s(%d)-%d",
|
||||
context->dev_priv->device->name,
|
||||
context->device->name,
|
||||
current->group_leader->comm, current->group_leader->pid,
|
||||
current->comm, current->pid, context->id);
|
||||
|
||||
@@ -250,7 +250,7 @@ int kgsl_sync_timeline_create(struct kgsl_context *context)
|
||||
|
||||
ktimeline = (struct kgsl_sync_timeline *) context->timeline;
|
||||
ktimeline->last_timestamp = 0;
|
||||
ktimeline->device = context->dev_priv->device;
|
||||
ktimeline->device = context->device;
|
||||
ktimeline->context_id = context->id;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -678,6 +678,28 @@ TRACE_EVENT(kgsl_context_detach,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kgsl_context_destroy,
|
||||
|
||||
TP_PROTO(struct kgsl_device *device, struct kgsl_context *context),
|
||||
|
||||
TP_ARGS(device, context),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device_name, device->name)
|
||||
__field(unsigned int, id)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device_name, device->name);
|
||||
__entry->id = context->id;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"d_name=%s ctx=%u",
|
||||
__get_str(device_name), __entry->id
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kgsl_mmu_pagefault,
|
||||
|
||||
TP_PROTO(struct kgsl_device *device, unsigned int page,
|
||||
|
||||
+31
-5
@@ -859,11 +859,30 @@ static int z180_wait(struct kgsl_device *device,
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
z180_drawctxt_destroy(struct kgsl_device *device,
|
||||
struct kgsl_context *context)
|
||||
struct kgsl_context *
|
||||
z180_drawctxt_create(struct kgsl_device_private *dev_priv,
|
||||
uint32_t *flags)
|
||||
{
|
||||
struct z180_device *z180_dev = Z180_DEVICE(device);
|
||||
int ret;
|
||||
struct kgsl_context *context = kzalloc(sizeof(*context), GFP_KERNEL);
|
||||
if (context == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = kgsl_context_init(dev_priv, context);
|
||||
if (ret != 0) {
|
||||
kfree(context);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
static void
|
||||
z180_drawctxt_detach(struct kgsl_context *context)
|
||||
{
|
||||
struct kgsl_device *device;
|
||||
struct z180_device *z180_dev;
|
||||
|
||||
device = context->device;
|
||||
z180_dev = Z180_DEVICE(device);
|
||||
|
||||
z180_idle(device);
|
||||
|
||||
@@ -875,6 +894,12 @@ z180_drawctxt_destroy(struct kgsl_device *device,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
z180_drawctxt_destroy(struct kgsl_context *context)
|
||||
{
|
||||
kfree(context);
|
||||
}
|
||||
|
||||
static void z180_power_stats(struct kgsl_device *device,
|
||||
struct kgsl_power_stats *stats)
|
||||
{
|
||||
@@ -941,7 +966,8 @@ static const struct kgsl_functable z180_functable = {
|
||||
.gpuid = z180_gpuid,
|
||||
.irq_handler = z180_irq_handler,
|
||||
/* Optional functions */
|
||||
.drawctxt_create = NULL,
|
||||
.drawctxt_create = z180_drawctxt_create,
|
||||
.drawctxt_detach = z180_drawctxt_detach,
|
||||
.drawctxt_destroy = z180_drawctxt_destroy,
|
||||
.ioctl = NULL,
|
||||
.postmortem_dump = z180_dump,
|
||||
|
||||
Reference in New Issue
Block a user