Commit 16356049 authored by Jeff Boody's avatar Jeff Boody Committed by Carter Cooper
Browse files

msm: kgsl: update KGSL to match most recent version


Over time chery-picks for KGSL have been skipped or
have been resolved differently between branches. As
a result, this branch of KGSL has become increasingly
difficult to maintain due to merge conflicts. With a
few exceptions KGSL should match the msm-3.4 mainline
exactly. To rectify the situation, this change brings
KGSL up-to-date with the msm-3.4 mainline as a bulk
change because cherry-picks are not practical.

Change-Id: I53f9f7fbf4942e147dea486ff5dbf179af75ea8c
Signed-off-by: default avatarJeff Boody <jboody@codeaurora.org>
parent edcc061a
......@@ -25,8 +25,8 @@ msm_adreno-y += \
adreno_dispatch.o \
adreno_postmortem.o \
adreno_snapshot.o \
adreno_trace.o \
adreno_coresight.o \
adreno_trace.o \
adreno_a2xx.o \
adreno_a2xx_trace.o \
adreno_a2xx_snapshot.o \
......
/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2007-2013, The Linux Foundation. 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
......@@ -252,7 +252,15 @@ union reg_cp_rb_cntl {
#define REG_CP_CSQ_IB1_STAT 0x01FE
#define REG_CP_CSQ_IB2_STAT 0x01FF
#define REG_CP_CSQ_RB_STAT 0x01FD
#define REG_CP_DEBUG 0x01FC
/*
* CP DEBUG settings for a3xx and a2xx cores:
* DYNAMIC_CLK_DISABLE [27] - turn off the dynamic clock control
* MIU_128BIT_WRITE_ENABLE [25] - Allow 128 bit writes to the VBIF
*/
#define A2XX_CP_DEBUG_DEFAULT ((1 << 27) | (1 << 25))
#define REG_CP_IB1_BASE 0x0458
#define REG_CP_IB1_BUFSZ 0x0459
#define REG_CP_IB2_BASE 0x045A
......
......@@ -17,7 +17,6 @@
#include <linux/sched.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/msm_kgsl.h>
#include <linux/delay.h>
#include <linux/of_coresight.h>
......@@ -162,6 +161,12 @@ static const struct {
unsigned int pfp_jt_idx;
/* PFP jump table load addr */
unsigned int pfp_jt_addr;
/* PM4 bootstrap loader size */
unsigned int pm4_bstrp_size;
/* PFP bootstrap loader size */
unsigned int pfp_bstrp_size;
/* PFP bootstrap loader supported version */
unsigned int pfp_bstrp_ver;
} adreno_gpulist[] = {
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
......@@ -199,7 +204,8 @@ static const struct {
512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
{ ADRENO_REV_A330, 3, 3, 0, ANY_ID,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_1M, NO_VER, NO_VER, 0x8AD, 0x2E4, 0x201, 0x200 },
512, 0, 2, SZ_1M, NO_VER, NO_VER, 0x8AD, 0x2E4, 0x201, 0x200,
0x6, 0x20, 0x330020 },
{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
......@@ -928,7 +934,7 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
*cmds++ = 0x7fff;
sizedwords += 2;
if (sizedwords > (sizeof(link)/sizeof(unsigned int))) {
if (sizedwords > (ARRAY_SIZE(link))) {
KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
BUG();
}
......@@ -982,6 +988,7 @@ static int adreno_gpummu_setstate(struct kgsl_device *device,
context = kgsl_context_get(device, context_id);
if (context == NULL)
return -EINVAL;
adreno_ctx = ADRENO_CONTEXT(context);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
......@@ -1197,8 +1204,11 @@ adreno_identify_gpu(struct adreno_device *adreno_dev)
adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
adreno_dev->pm4_jt_idx = adreno_gpulist[i].pm4_jt_idx;
adreno_dev->pm4_jt_addr = adreno_gpulist[i].pm4_jt_addr;
adreno_dev->pm4_bstrp_size = adreno_gpulist[i].pm4_bstrp_size;
adreno_dev->pfp_jt_idx = adreno_gpulist[i].pfp_jt_idx;
adreno_dev->pfp_jt_addr = adreno_gpulist[i].pfp_jt_addr;
adreno_dev->pfp_bstrp_size = adreno_gpulist[i].pfp_bstrp_size;
adreno_dev->pfp_bstrp_ver = adreno_gpulist[i].pfp_bstrp_ver;
adreno_dev->gpulist_index = i;
/*
* Initialize uninitialzed gpu registers, only needs to be done once
......@@ -1607,7 +1617,6 @@ static int __devexit adreno_remove(struct platform_device *pdev)
static int adreno_init(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
int i;
int ret;
......@@ -1655,8 +1664,6 @@ static int adreno_init(struct kgsl_device *device)
adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
rb->global_ts = 0;
/* Initialize ft detection register offsets */
ft_detect_regs[0] = adreno_getreg(adreno_dev,
ADRENO_REG_RBBM_STATUS);
......@@ -1685,7 +1692,6 @@ static int adreno_init(struct kgsl_device *device)
if (adreno_is_a330v2(adreno_dev))
adreno_a3xx_pwron_fixup_init(adreno_dev);
set_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv);
done:
return ret;
}
......@@ -1709,7 +1715,7 @@ static int adreno_start(struct kgsl_device *device)
regulator_is_enabled(device->pwrctrl.gpu_cx)));
/* Clear any GPU faults that might have been left over */
adreno_set_gpu_fault(adreno_dev, 0);
adreno_clear_gpu_fault(adreno_dev);
/* Power up the device */
kgsl_pwrctrl_enable(device);
......@@ -1755,7 +1761,7 @@ static int adreno_start(struct kgsl_device *device)
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
device->ftbl->irqctrl(device, 1);
status = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
status = adreno_ringbuffer_cold_start(&adreno_dev->ringbuffer);
if (status)
goto error_irq_off;
......@@ -1822,7 +1828,9 @@ static int adreno_stop(struct kgsl_device *device)
* adreno_reset() - Helper function to reset the GPU
* @device: Pointer to the KGSL device structure for the GPU
*
* Helper function to reset the GPU hardware by toggling the footswitch
* Try to reset the GPU to recover from a fault. First, try to do a low latency
* soft reset. If the soft reset fails for some reason, then bring out the big
* guns and toggle the footswitch.
*/
int adreno_reset(struct kgsl_device *device)
{
......@@ -2301,6 +2309,7 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
}
if (enable) {
device->pwrctrl.ctrl_flags = 0;
adreno_dev->fast_hang_detect = 1;
kgsl_pwrscale_enable(device);
} else {
......@@ -2358,7 +2367,6 @@ static bool adreno_hw_isidle(struct kgsl_device *device)
if (adreno_dev->gpudev->irq_pending(adreno_dev))
return false;
/* Read the correct RBBM status for the GPU type */
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
&reg_rbbm_status);
......@@ -2391,6 +2399,9 @@ int adreno_soft_reset(struct kgsl_device *device)
return -EINVAL;
}
if (adreno_dev->drawctxt_active)
kgsl_context_put(&adreno_dev->drawctxt_active->base);
adreno_dev->drawctxt_active = NULL;
/* Stop the ringbuffer */
......@@ -2401,7 +2412,7 @@ int adreno_soft_reset(struct kgsl_device *device)
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
adreno_set_gpu_fault(adreno_dev, 0);
adreno_clear_gpu_fault(adreno_dev);
/* Delete the idle timer */
del_timer_sync(&device->idle_timer);
......@@ -2427,7 +2438,7 @@ int adreno_soft_reset(struct kgsl_device *device)
if (adreno_dev->pm4_jt_idx)
ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
else
ret = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
ret = adreno_ringbuffer_cold_start(&adreno_dev->ringbuffer);
if (ret)
return ret;
......@@ -2437,7 +2448,7 @@ int adreno_soft_reset(struct kgsl_device *device)
return 0;
}
/**
/*
* adreno_isidle() - return true if the GPU hardware is idle
* @device: Pointer to the KGSL device structure for the GPU
*
......@@ -2449,8 +2460,7 @@ bool adreno_isidle(struct kgsl_device *device)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int rptr;
/* If the device isn't active, don't force it on. */
if (device->state != KGSL_STATE_ACTIVE)
if (!kgsl_pwrctrl_isenabled(device))
return true;
rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
......@@ -2483,7 +2493,7 @@ int adreno_idle(struct kgsl_device *device)
if (adreno_is_a3xx(adreno_dev) || adreno_is_a4xx(adreno_dev))
kgsl_cffdump_regpoll(device,
adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
0x00000000, 0x80000000);
0x00000000, 0x80000000);
else
kgsl_cffdump_regpoll(device,
adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
......@@ -2752,6 +2762,15 @@ static int adreno_waittimestamp(struct kgsl_device *device,
if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
ret = -EDEADLK;
/*
* Return -EPROTO if the device has faulted since the last time we
* checked. Userspace uses this as a marker for performing post
* fault activities
*/
if (!ret && test_and_clear_bit(ADRENO_CONTEXT_FAULT, &drawctxt->priv))
ret = -EPROTO;
return ret;
}
......
......@@ -58,7 +58,6 @@
#define ADRENO_DEFAULT_PWRSCALE_POLICY NULL
#endif
void adreno_debugfs_init(struct kgsl_device *device);
#define ADRENO_ISTORE_START 0x5000 /* Istore offset */
......@@ -168,8 +167,11 @@ struct adreno_device {
unsigned int wait_timeout;
unsigned int pm4_jt_idx;
unsigned int pm4_jt_addr;
unsigned int pm4_bstrp_size;
unsigned int pfp_jt_idx;
unsigned int pfp_jt_addr;
unsigned int pfp_bstrp_size;
unsigned int pfp_bstrp_ver;
unsigned int istore_size;
unsigned int pix_shader_start;
unsigned int instruction_size;
......@@ -379,8 +381,8 @@ struct adreno_gpudev {
void (*coresight_disable) (struct kgsl_device *device);
void (*coresight_config_debug_reg) (struct kgsl_device *device,
int debug_reg, unsigned int val);
void (*postmortem_dump)(struct adreno_device *adreno_dev);
void (*soft_reset)(struct adreno_device *device);
void (*postmortem_dump)(struct adreno_device *adreno_dev);
};
#define FT_DETECT_REGS_COUNT 12
......@@ -726,13 +728,13 @@ static inline int adreno_add_idle_cmds(struct adreno_device *adreno_dev,
unsigned int *start = cmds;
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0x00000000;
*cmds++ = 0;
if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
(adreno_dev->gpurev == ADRENO_REV_A305C) ||
(adreno_dev->gpurev == ADRENO_REV_A320)) {
*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
*cmds++ = 0x00000000;
*cmds++ = 0;
}
return cmds - start;
......@@ -849,6 +851,19 @@ static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
smp_wmb();
}
/**
* adreno_clear_gpu_fault() - Clear the GPU fault register
* @adreno_dev: A pointer to an adreno_device structure
*
* Clear the GPU fault status for the adreno device
*/
static inline void adreno_clear_gpu_fault(struct adreno_device *adreno_dev)
{
atomic_set(&adreno_dev->dispatcher.fault, 0);
smp_wmb();
}
/*
* adreno_vbif_start() - Program VBIF registers, called in device start
* @device: Pointer to device whose vbif data is to be programmed
......@@ -877,6 +892,25 @@ static inline void adreno_vbif_start(struct kgsl_device *device,
}
}
#ifdef CONFIG_DEBUG_FS
void adreno_debugfs_init(struct kgsl_device *device);
#else
static inline void adreno_debugfs_init(struct kgsl_device *device) { }
#endif
/*
* adreno_bootstrap_ucode() - Checks if Ucode bootstrapping is supported
* @adreno_dev: Pointer to the the adreno device
*/
static inline int adreno_bootstrap_ucode(struct adreno_device *adreno_dev)
{
if ((adreno_dev->pfp_bstrp_size) && (adreno_dev->pm4_bstrp_size)
&& (adreno_dev->pfp_fw_version >= adreno_dev->pfp_bstrp_ver))
return 1;
else
return 0;
}
/**
* adreno_get_rptr() - Get the current ringbuffer read pointer
* @rb: Pointer the ringbuffer to query
......
......@@ -655,7 +655,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)) {
if (!(drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE)) {
/* Store TP0_CHICKEN register */
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
*cmds++ = REG_TP0_CHICKEN;
......@@ -864,7 +864,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)) {
if (!(drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE)) {
/* Store TP0_CHICKEN register */
*cmds++ = cp_type3_packet(CP_REG_TO_MEM, 2);
*cmds++ = REG_TP0_CHICKEN;
......@@ -1334,8 +1334,6 @@ build_shader_save_restore_cmds(struct adreno_device *adreno_dev,
static int a2xx_create_gpustate_shadow(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;
/* build indirect command buffers to save & restore regs/constants */
build_regrestore_cmds(adreno_dev, drawctxt);
build_regsave_cmds(adreno_dev, drawctxt);
......@@ -1361,9 +1359,6 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
if (result)
return result;
/* set the gmem shadow flag for the context */
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
/* blank out gmem shadow. */
kgsl_sharedmem_set(drawctxt->base.device,
&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
......@@ -1374,7 +1369,7 @@ static int a2xx_create_gmem_shadow(struct adreno_device *adreno_dev,
&tmp_ctx.cmd);
/* build TP0_CHICKEN register restore command buffer */
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE))
if (!(drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE))
tmp_ctx.cmd = build_chicken_restore_cmds(drawctxt);
/* build indirect command buffers to save & restore gmem */
......@@ -1437,8 +1432,8 @@ static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
{
int ret;
if (drawctxt->flags & CTXT_FLAGS_PREAMBLE
&& drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC) {
if (drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE
&& drawctxt->base.flags & KGSL_CONTEXT_NO_GMEM_ALLOC) {
drawctxt->ops = (adreno_is_a225(adreno_dev))
? &a225_preamble_ctx_ops : &adreno_preamble_ctx_ops;
......@@ -1467,15 +1462,14 @@ static int a2xx_drawctxt_create(struct adreno_device *adreno_dev,
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(drawctxt->base.flags & KGSL_CONTEXT_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)) {
if (!(drawctxt->base.flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
ret = a2xx_create_gmem_shadow(adreno_dev, drawctxt);
if (ret)
goto done;
......@@ -1555,7 +1549,7 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
struct kgsl_device *device = &adreno_dev->dev;
int ret;
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->reg_save[1],
context->reg_save[2] << 2, true);
......@@ -1567,7 +1561,7 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
if (ret)
return ret;
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
if (test_bit(ADRENO_CONTEXT_SHADER_SAVE, &context->priv)) {
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_save[1],
......@@ -1577,6 +1571,8 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
if (ret)
return ret;
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_fixup[1],
......@@ -1592,12 +1588,11 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
if (ret)
return ret;
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
set_bit(ADRENO_CONTEXT_SHADER_RESTORE, &context->priv);
}
}
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
if (test_bit(ADRENO_CONTEXT_GMEM_SAVE, &context->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);
......@@ -1610,12 +1605,13 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
if (ret)
return ret;
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
/* Restore TP0_CHICKEN */
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
......@@ -1625,7 +1621,7 @@ static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
}
adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
set_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv);
} else if (adreno_is_a2xx(adreno_dev))
return a2xx_drawctxt_draw_workaround(adreno_dev, context);
......@@ -1646,7 +1642,7 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
* restore gmem.
* (note: changes shader. shader must not already be restored.)
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
if (test_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv)) {
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
......@@ -1658,7 +1654,7 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
if (ret)
return ret;
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->chicken_restore[1],
......@@ -1671,11 +1667,10 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
if (ret)
return ret;
}
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
clear_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv);
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
context->reg_restore[1],
context->reg_restore[2] << 2, true);
......@@ -1687,7 +1682,7 @@ static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
return ret;
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
if (test_bit(ADRENO_CONTEXT_SHADER_RESTORE, &context->priv)) {
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->shader_restore[1],
......@@ -2093,6 +2088,8 @@ static void a2xx_start(struct adreno_device *adreno_dev)
kgsl_regwrite(device, REG_SQ_INT_CNTL, 0);
a2xx_gmeminit(adreno_dev);
kgsl_regwrite(device, REG_CP_DEBUG, A2XX_CP_DEBUG_DEFAULT);
}
static void a2xx_postmortem_dump(struct adreno_device *adreno_dev)
......
......@@ -2297,8 +2297,6 @@ static void build_restore_fixup_cmds(struct adreno_device *adreno_dev,
static int a3xx_create_gpustate_shadow(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
drawctxt->flags |= CTXT_FLAGS_STATE_SHADOW;
build_regrestore_cmds(adreno_dev, drawctxt);
build_constantrestore_cmds(adreno_dev, drawctxt);
build_hlsqcontrol_restore_cmds(adreno_dev, drawctxt);
......@@ -2338,8 +2336,6 @@ static int a3xx_create_gmem_shadow(struct adreno_device *adreno_dev,
kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
KGSL_CACHE_OP_FLUSH);
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
return 0;
}
......@@ -2371,8 +2367,8 @@ static int a3xx_drawctxt_create(struct adreno_device *adreno_dev,
* Nothing to do here if the context is using preambles and doesn't need
* GMEM save/restore
*/
if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC)) {
if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) &&
(drawctxt->base.flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
drawctxt->ops = &adreno_preamble_ctx_ops;
return 0;
}
......@@ -2388,15 +2384,15 @@ static int a3xx_drawctxt_create(struct adreno_device *adreno_dev,
CONTEXT_SIZE);
tmp_ctx.cmd = drawctxt->gpustate.hostptr + CMD_OFFSET;
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE)) {
ret = a3xx_create_gpustate_shadow(adreno_dev, drawctxt);
if (ret)
goto done;
drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
set_bit(ADRENO_CONTEXT_SHADER_SAVE, &drawctxt->priv);
}
if (!(drawctxt->flags & CTXT_FLAGS_NOGMEMALLOC))
if (!(drawctxt->base.flags & KGSL_CONTEXT_NO_GMEM_ALLOC))
ret = a3xx_create_gmem_shadow(adreno_dev, drawctxt);
done:
......@@ -2415,7 +2411,7 @@ static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
if (context->state == ADRENO_CONTEXT_STATE_INVALID)
return 0;
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
/* Fixup self modifying IBs for save operations */
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, context->save_fixup, 3);
......@@ -2429,19 +2425,17 @@ static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
if (ret)
return ret;
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
if (test_bit(ADRENO_CONTEXT_SHADER_SAVE, &context->priv)) {
/* Save shader instructions */
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_PMODE, context->shader_save, 3);
if (ret)
return ret;
context->flags |= CTXT_FLAGS_SHADER_RESTORE;
set_bit(ADRENO_CONTEXT_SHADER_RESTORE, &context->priv);
}
}
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
if (test_bit(ADRENO_CONTEXT_GMEM_SAVE, &context->priv)) {
/*
* Save GMEM (note: changes shader. shader must
* already be saved.)
......@@ -2459,7 +2453,7 @@ static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
if (ret)
return ret;
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
set_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv);
}
return 0;
......@@ -2481,7 +2475,7 @@ static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
* Shader must not already be restored.)
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
if (test_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv)) {
kgsl_cffdump_syncmem(context->base.device,
&context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
......@@ -2494,10 +2488,10 @@ static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
gmem_restore, 3);
if (ret)
return ret;
context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
clear_bit(ADRENO_CONTEXT_GMEM_RESTORE, &context->priv);
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
if (!(context->base.flags & KGSL_CONTEXT_PREAMBLE)) {
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
if (ret)
......@@ -2516,12 +2510,13 @@ static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
if (ret)
return ret;
if (context->flags & CTXT_FLAGS_SHADER_RESTORE)
if (test_bit(ADRENO_CONTEXT_SHADER_RESTORE, &context->priv)) {
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
context->shader_restore, 3);
if (ret)
return ret;
}
/* Restore HLSQ_CONTROL_0 register */
ret = adreno_ringbuffer_issuecmds(device, context,
KGSL_CMD_FLAGS_NONE,
......@@ -3137,7 +3132,6 @@ static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
device->pwrctrl.irq_last = 1;
queue_work(device->work_queue, &device->ts_expired_ws);
adreno_dispatcher_schedule(device);
}
......@@ -3427,7 +3421,7 @@ static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev,
static struct {
void (*func)(struct adreno_device *, int);
} a3xx_irq_funcs[] = {
A3XX_IRQ_CALLBACK(NULL), /* 0 - RBBM_GPU_IDLE */
A3XX_IRQ_CALLBACK(NULL), /* 0 - RBBM_GPU_IDLE */
A3XX_IRQ_CALLBACK(a3xx_err_callback), /* 1 - RBBM_AHB_ERROR */
A3XX_IRQ_CALLBACK(a3xx_err_callback), /* 2 - RBBM_REG_TIMEOUT */
A3XX_IRQ_CALLBACK(a3xx_err_callback), /* 3 - RBBM_ME_MS_TIMEOUT */
......@@ -4036,6 +4030,9 @@ static void a3xx_start(struct adreno_device *adreno_dev)
/* Turn on the GPU busy counter and let it run free */
adreno_dev->gpu_cycles = 0;
/* the CP_DEBUG register offset and value are same as A2XX */
kgsl_regwrite(device, REG_CP_DEBUG, A2XX_CP_DEBUG_DEFAULT);
}
/**
......@@ -4419,6 +4416,6 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
.coresight_enable = a3xx_coresight_enable,
.coresight_disable = a3xx_coresight_disable,
.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
.postmortem_dump = a3xx_postmortem_dump,
.soft_reset = a3xx_soft_reset,
.postmortem_dump = a3xx_postmortem_dump,
};
......@@ -277,7 +277,6 @@ static int a3xx_snapshot_debugbus_block(struct kgsl_device *device,
struct kgsl_snapshot_debugbus *header = snapshot;
struct debugbus_block *block = priv;
unsigned int val;
int i;
unsigned int *data = snapshot + sizeof(*header);
unsigned int dwords;
......@@ -300,8 +299,6 @@ static int a3xx_snapshot_debugbus_block(struct kgsl_device *device,
return 0;
}
val = (block->block_id << 8) | (1 << 16);
header->id = block->block_id;
header->count = dwords;
......
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2013, The Linux Foundation. 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
......@@ -48,7 +48,7 @@ TRACE_EVENT(kgsl_a3xx_irq_status,
"d_name=%s status=%s",
__get_str(device_name),
__entry->status ? __print_flags(__entry->status, "|",
{ 1 << A3XX_INT_RBBM_AHB_ERROR, "RBBM_GPU_IDLE" },
{ 1 << A3XX_INT_RBBM_GPU_IDLE, "RBBM_GPU_IDLE" },
{ 1 << A3XX_INT_RBBM_AHB_ERROR, "RBBM_AHB_ERR" },
{ 1 << A3XX_INT_RBBM_REG_TIMEOUT, "RBBM_REG_TIMEOUT" },
{ 1 << A3XX_INT_RBBM_ME_MS_TIMEOUT,
......
/* Copyright (c) 2002,2008-2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2008-2013, The Linux Foundation. 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
......@@ -23,8 +23,6 @@
#include "a2xx_reg.h"
unsigned int kgsl_cff_dump_enable;
DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
kgsl_cff_dump_enable_set, "%llu\n");
......@@ -56,41 +54,6 @@ void adreno_debugfs_init(struct kgsl_device *device)
&adreno_dev->wait_timeout);
debugfs_create_u32("ib_check", 0644, device->d_debugfs,
&adreno_dev->ib_check_level);
/* By Default enable fast hang detection */
adreno_dev->fast_hang_detect = 1;
debugfs_create_u32("fast_hang_detect", 0644, device->d_debugfs,
&adreno_dev->fast_hang_detect);
/*
* FT policy can be set to any of the options below.
* KGSL_FT_OFF -> BIT(0) Set to turn off FT
* KGSL_FT_REPLAY -> BIT(1) Set to enable replay
* KGSL_FT_SKIPIB -> BIT(2) Set to skip IB
* KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame
* KGSL_FT_DISABLE -> BIT(4) Set to disable FT for faulting context
* by default set FT policy to KGSL_FT_DEFAULT_POLICY
*/
adreno_dev->ft_policy = KGSL_FT_DEFAULT_POLICY;
debugfs_create_u32("ft_policy", 0644, device->d_debugfs,
&adreno_dev->ft_policy);
/* By default enable long IB detection */
adreno_dev->long_ib_detect = 1;
debugfs_create_u32("long_ib_detect", 0644, device->d_debugfs,
&adreno_dev->long_ib_detect);
/*
* FT pagefault policy can be set to any of the options below.
* KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT
* KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on
* pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW.
* KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one
* pagefault per page.
* KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one
* pagefault per INT.
*/
adreno_dev->ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY;
debugfs_create_u32("ft_pagefault_policy", 0644, device->d_debugfs,
&adreno_dev->ft_pf_policy);
debugfs_create_file("active_cnt", 0444, device->d_debugfs, device,
&_active_count_fops);
}
......@@ -233,7 +233,6 @@ static void dispatcher_queue_context(struct adreno_device *adreno_dev,
spin_lock(&dispatcher->plist_lock);
if (plist_node_empty(&drawctxt->pending)) {
/* Get a reference to the context while it sits on the list */
if (_kgsl_context_get(&drawctxt->base)) {
......@@ -569,7 +568,7 @@ static int get_timestamp(struct adreno_context *drawctxt,
return 0;
}
if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
if (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS) {
/*
* User specified timestamps need to be greater than the last
* issued timestamp in the context
......@@ -586,7 +585,7 @@ static int get_timestamp(struct adreno_context *drawctxt,
}
/**
* adreno_dispatcher_queue_cmd() - Queue a new command in the context
* adreno_dispactcher_queue_cmd() - Queue a new command in the context
* @adreno_dev: Pointer to the adreno device struct
* @drawctxt: Pointer to the adreno draw context
* @cmdbatch: Pointer to the command batch being submitted
......@@ -613,10 +612,8 @@ int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
* to run (if it exists) regardless of the context state.
*/
if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) {
if (test_and_clear_bit(ADRENO_CONTEXT_FORCE_PREAMBLE, &drawctxt->priv))
set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE;
}
/*
* If we are waiting for the end of frame and it hasn't appeared yet,
......@@ -624,7 +621,7 @@ int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
* through the pipeline but it won't actually send any commands
*/
if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
if (test_bit(ADRENO_CONTEXT_SKIP_EOF, &drawctxt->priv)) {
set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
/*
......@@ -633,14 +630,13 @@ int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
*/
if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) {
drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
clear_bit(ADRENO_CONTEXT_SKIP_EOF, &drawctxt->priv);
/*
* Force the preamble on the next command to ensure that
* the state is correct
*/
drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
set_bit(ADRENO_CONTEXT_FORCE_PREAMBLE, &drawctxt->priv);
}
}
......@@ -686,10 +682,10 @@ int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
/*
* Set the fault tolerance policy for the command batch - assuming the
* context hsn't disabled FT use the current device policy
* context hasn't disabled FT use the current device policy
*/
if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
if (drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy);
else
cmdbatch->fault_policy = adreno_dev->ft_policy;
......@@ -723,6 +719,44 @@ int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
return 0;
}
static int _mark_context(int id, void *ptr, void *data)
{
unsigned int guilty = *((unsigned int *) data);
struct kgsl_context *context = ptr;
/*
* If the context is guilty mark it as such. Otherwise mark it as
* innocent if it had not already been marked as guilty. If id is
* passed as 0 then mark EVERYBODY guilty (recovery failed)
*/
if (guilty == 0 || guilty == context->id)
context->reset_status =
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
else if (context->reset_status !=
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT)
context->reset_status =
KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
return 0;
}
/**
* mark_guilty_context() - Mark the given context as guilty (failed recovery)
* @device: Pointer to a KGSL device structure
* @id: Context ID of the guilty context (or 0 to mark all as guilty)
*
* Mark the given (or all) context(s) as guilty (failed recovery)
*/
static void mark_guilty_context(struct kgsl_device *device, unsigned int id)
{
/* Mark the status for all the contexts in the device */
read_lock(&device->context_lock);
idr_for_each(&device->context_idr, _mark_context, &id);
read_unlock(&device->context_lock);
}
/*
* If an IB inside of the command batch has a gpuaddr that matches the base
* passed in then zero the size which effectively skips it when it is submitted
......@@ -781,7 +815,7 @@ static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
*/
if (skip && drawctxt)
drawctxt->flags |= CTXT_FLAGS_SKIP_EOF;
set_bit(ADRENO_CONTEXT_SKIP_EOF, &drawctxt->priv);
/*
* If we did see the EOF flag then force the preamble on for the
......@@ -789,7 +823,7 @@ static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
*/
if (!skip && drawctxt)
drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
set_bit(ADRENO_CONTEXT_FORCE_PREAMBLE, &drawctxt->priv);
}
static void remove_invalidated_cmdbatches(struct kgsl_device *device,
......@@ -956,6 +990,9 @@ static int dispatcher_do_fault(struct kgsl_device *device)
if (replay == NULL) {
unsigned int ptr = dispatcher->head;
/* Recovery failed - mark everybody guilty */
mark_guilty_context(device, 0);
while (ptr != dispatcher->tail) {
struct kgsl_context *context =
dispatcher->cmdqueue[ptr]->context;
......@@ -1028,6 +1065,7 @@ static int dispatcher_do_fault(struct kgsl_device *device)
pr_fault(device, cmdbatch, "gpu skipped ctx %d ts %d\n",
cmdbatch->context->id, cmdbatch->timestamp);
mark_guilty_context(device, cmdbatch->context->id);
adreno_drawctxt_invalidate(device, cmdbatch->context);
}
......@@ -1123,6 +1161,9 @@ static int dispatcher_do_fault(struct kgsl_device *device)
pr_fault(device, cmdbatch, "gpu failed ctx %d ts %d\n",
cmdbatch->context->id, cmdbatch->timestamp);
/* Mark the context as failed */
mark_guilty_context(device, cmdbatch->context->id);
/* Invalidate the context */
adreno_drawctxt_invalidate(device, cmdbatch->context);
......@@ -1183,6 +1224,9 @@ replay:
"gpu reset failed ctx %d ts %d\n",
replay[i]->context->id, replay[i]->timestamp);
/* Mark this context as guilty (failed recovery) */
mark_guilty_context(device, replay[i]->context->id);
adreno_drawctxt_invalidate(device, replay[i]->context);
remove_invalidated_cmdbatches(device, &replay[i],
count - i);
......@@ -1239,6 +1283,7 @@ static void adreno_dispatcher_work(struct work_struct *work)
container_of(dispatcher, struct adreno_device, dispatcher);
struct kgsl_device *device = &adreno_dev->dev;
int count = 0;
int last_context = KGSL_CONTEXT_INVALID;
int fault_handled = 0;
mutex_lock(&dispatcher->mutex);
......@@ -1270,12 +1315,22 @@ static void adreno_dispatcher_work(struct work_struct *work)
* successful completion to the world
*/
if (cmdbatch->fault_recovery != 0)
if (cmdbatch->fault_recovery != 0) {
struct adreno_context *drawctxt =
ADRENO_CONTEXT(cmdbatch->context);
/* Mark the context as faulted and recovered */
set_bit(ADRENO_CONTEXT_FAULT, &drawctxt->priv);
_print_recovery(device, cmdbatch);
}
trace_adreno_cmdbatch_retired(cmdbatch,
dispatcher->inflight - 1);
/* Remember the last context that got retired */
last_context = cmdbatch->context->id;
/* Reduce the number of inflight command batches */
dispatcher->inflight--;
......@@ -1324,7 +1379,7 @@ static void adreno_dispatcher_work(struct work_struct *work)
*/
if (!adreno_dev->long_ib_detect ||
drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
break;
/*
......@@ -1380,6 +1435,18 @@ done:
/* Update the timeout timer for the next command batch */
mod_timer(&dispatcher->timer, cmdbatch->expires);
/*
* if the context for the next pending cmdbatch is different
* than the last one we retired, then trace it as a GPU switch
*/
if (cmdbatch->context->id != last_context) {
u64 now = ktime_to_ns(ktime_get());
kgsl_trace_gpu_sched_switch(device->name, now,
cmdbatch->context->id, cmdbatch->priority,
cmdbatch->timestamp);
}
/* There are still things in flight - update the idle counts */
mutex_lock(&device->mutex);
kgsl_pwrscale_idle(device);
......@@ -1498,7 +1565,6 @@ void adreno_dispatcher_irq_fault(struct kgsl_device *device)
* adreno_dispatcher_start() - activate the dispatcher
* @adreno_dev: pointer to the adreno device structure
*
* Set the disaptcher active and start the loop once to get things going
*/
void adreno_dispatcher_start(struct kgsl_device *device)
{
......
......@@ -412,6 +412,7 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
int ret;
drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
if (drawctxt == NULL)
return ERR_PTR(-ENOMEM);
......@@ -424,7 +425,7 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
drawctxt->bin_base_offset = 0;
drawctxt->timestamp = 0;
*flags &= (KGSL_CONTEXT_PREAMBLE |
drawctxt->base.flags = *flags & (KGSL_CONTEXT_PREAMBLE |
KGSL_CONTEXT_NO_GMEM_ALLOC |
KGSL_CONTEXT_PER_CONTEXT_TS |
KGSL_CONTEXT_USER_GENERATED_TS |
......@@ -433,20 +434,7 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
KGSL_CONTEXT_PWR_CONSTRAINT);
/* Always enable per-context timestamps */
*flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
if (*flags & KGSL_CONTEXT_PREAMBLE)
drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
if (*flags & KGSL_CONTEXT_USER_GENERATED_TS)
drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
if (*flags & KGSL_CONTEXT_PWR_CONSTRAINT)
drawctxt->flags |= CTXT_FLAGS_PWR_CONSTRAINT;
drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
mutex_init(&drawctxt->mutex);
init_waitqueue_head(&drawctxt->wq);
......@@ -460,18 +448,12 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
plist_node_init(&drawctxt->pending, ADRENO_CONTEXT_DEFAULT_PRIORITY);
if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
drawctxt->type =
(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
if (adreno_dev->gpudev->ctxt_create) {
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
} else if ((*flags & KGSL_CONTEXT_PREAMBLE) == 0 ||
(*flags & KGSL_CONTEXT_NO_GMEM_ALLOC) == 0) {
} else if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) == 0 ||
(drawctxt->base.flags & KGSL_CONTEXT_NO_GMEM_ALLOC) == 0) {
KGSL_DEV_ERR_ONCE(device,
"legacy context switch not supported\n");
ret = -EINVAL;
......@@ -487,7 +469,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
0);
/* copy back whatever flags we dediced were valid */
*flags = drawctxt->base.flags;
return &drawctxt->base;
err:
kgsl_context_detach(&drawctxt->base);
......@@ -715,10 +698,10 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
if (flags & KGSL_CONTEXT_SAVE_GMEM)
/* Set the flag in context so that the save is done
* when this context is switched out. */
drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
set_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
else
/* Remove GMEM saving flag from the context */
drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
clear_bit(ADRENO_CONTEXT_GMEM_SAVE, &drawctxt->priv);
}
/* already current? */
......
......@@ -16,46 +16,6 @@
#include "adreno_pm4types.h"
#include "a2xx_reg.h"
/* Flags */
#define CTXT_FLAGS_NOT_IN_USE 0x00000000
#define CTXT_FLAGS_IN_USE BIT(0)
/* state shadow memory allocated */
#define CTXT_FLAGS_STATE_SHADOW BIT(1)
/* gmem shadow memory allocated */
#define CTXT_FLAGS_GMEM_SHADOW BIT(2)
/* gmem must be copied to shadow */
#define CTXT_FLAGS_GMEM_SAVE BIT(3)
/* gmem can be restored from shadow */
#define CTXT_FLAGS_GMEM_RESTORE BIT(4)
/* preamble packed in cmdbuffer for context switching */
#define CTXT_FLAGS_PREAMBLE BIT(5)
/* shader must be copied to shadow */
#define CTXT_FLAGS_SHADER_SAVE BIT(6)
/* shader can be restored from shadow */
#define CTXT_FLAGS_SHADER_RESTORE BIT(7)
/* Context has caused a GPU hang */
#define CTXT_FLAGS_GPU_HANG BIT(8)
/* Specifies there is no need to save GMEM */
#define CTXT_FLAGS_NOGMEMALLOC BIT(9)
/* Trash state for context */
#define CTXT_FLAGS_TRASHSTATE BIT(10)
/* per context timestamps enabled */
#define CTXT_FLAGS_PER_CONTEXT_TS BIT(11)
/* Context has caused a GPU hang and fault tolerance successful */
#define CTXT_FLAGS_GPU_HANG_FT BIT(12)
/* User mode generated timestamps enabled */
#define CTXT_FLAGS_USER_GENERATED_TS BIT(14)
/* Context skip till EOF */
#define CTXT_FLAGS_SKIP_EOF BIT(15)
/* Context no fault tolerance */
#define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16)
/* Force the preamble for the next submission */
#define CTXT_FLAGS_FORCE_PREAMBLE BIT(17)
/* power constraints enabled */
#define CTXT_FLAGS_PWR_CONSTRAINT BIT(18)
/* Symbolic table for the adreno draw context type */
#define ADRENO_DRAWCTXT_TYPES \
......@@ -132,7 +92,7 @@ extern const struct adreno_context_ops adreno_preamble_ctx_ops;
* @internal_timestamp: Global timestamp of the last issued command
* NOTE: guarded by device->mutex, not drawctxt->mutex!
* @state: Current state of the context
* @flags: Bitfield controlling behavior of the context
* @priv: Internal flags
* @type: Context type (GL, CL, RS)
* @mutex: Mutex to protect the cmdqueue
* @pagetable: Pointer to the GPU pagetable for the context
......@@ -171,7 +131,7 @@ struct adreno_context {
unsigned int timestamp;
unsigned int internal_timestamp;
int state;
uint32_t flags;
unsigned long priv;
unsigned int type;
struct mutex mutex;
struct kgsl_memdesc gpustate;
......@@ -202,8 +162,8 @@ struct adreno_context {
/* Dispatcher */
struct kgsl_cmdbatch *cmdqueue[ADRENO_CONTEXT_CMDQUEUE_SIZE];
int cmdqueue_head;
int cmdqueue_tail;
unsigned int cmdqueue_head;
unsigned int cmdqueue_tail;
struct plist_node pending;
wait_queue_head_t wq;
......@@ -214,6 +174,31 @@ struct adreno_context {
const struct adreno_context_ops *ops;
};
/**
* enum adreno_context_priv - Private flags for an adreno draw context
* @ADRENO_CONTEXT_FAULT - set if the context has faulted (and recovered)
* @ADRENO_CONTEXT_GMEM_SAVE - gmem must be copied to shadow
* @ADRENO_CONTEXT_GMEM_RESTORE - gmem can be restored from shadow
* @ADRENO_CONTEXT_SHADER_SAVE - shader must be copied to shadow
* @ADRENO_CONTEXT_SHADER_RESTORE - shader can be restored from shadow
* @ADRENO_CONTEXT_GPU_HANG - Context has caused a GPU hang
* @ADRENO_CONTEXT_GPU_HANG_FT - Context has caused a GPU hang
* and fault tolerance was successful
* @ADRENO_CONTEXT_SKIP_EOF - Context skip IBs until the next end of frame
* marker.
* @ADRENO_CONTEXT_FORCE_PREAMBLE - Force the preamble for the next submission.
*/
enum adreno_context_priv {
ADRENO_CONTEXT_FAULT = 0,
ADRENO_CONTEXT_GMEM_SAVE,
ADRENO_CONTEXT_GMEM_RESTORE,
ADRENO_CONTEXT_SHADER_SAVE,
ADRENO_CONTEXT_SHADER_RESTORE,
ADRENO_CONTEXT_GPU_HANG,
ADRENO_CONTEXT_GPU_HANG_FT,
ADRENO_CONTEXT_SKIP_EOF,
ADRENO_CONTEXT_FORCE_PREAMBLE,
};
struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
uint32_t *flags);
......
......@@ -143,10 +143,10 @@
#define CP_IM_STORE 0x2c
/* test 2 memory locations to dword values specified */
#define CP_TEST_TWO_MEMS 0x71
#define CP_TEST_TWO_MEMS 0x71
/* PFP waits until the FIFO between the PFP and the ME is empty */
#define CP_WAIT_FOR_ME 0x13
#define CP_WAIT_FOR_ME 0x13
/*
* for a20x
......@@ -164,6 +164,8 @@
#define CP_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */
#define CP_BOOTSTRAP_UCODE 0x6f /* bootstraps microcode */
/*
* for a3xx
*/
......
......@@ -12,6 +12,7 @@
*/
#include <linux/vmalloc.h>
#include <mach/board.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
......@@ -51,6 +52,7 @@ static const struct pm_id_name pm3_types[] = {
{CP_DRAW_INDX, "DRW_NDX_"},
{CP_DRAW_INDX_BIN, "DRW_NDXB"},
{CP_EVENT_WRITE, "EVENT_WT"},
{CP_MEM_WRITE, "MEM_WRIT"},
{CP_IM_LOAD, "IN__LOAD"},
{CP_IM_LOAD_IMMEDIATE, "IM_LOADI"},
{CP_IM_STORE, "IM_STORE"},
......
......@@ -30,14 +30,6 @@
#define GSL_RB_NOP_SIZEDWORDS 2
/*
* CP DEBUG settings for all cores:
* DYNAMIC_CLK_DISABLE [27] - turn off the dynamic clock control
* PROG_END_PTR_ENABLE [25] - Allow 128 bit writes to the VBIF
*/
#define CP_DEBUG_DEFAULT ((1 << 27) | (1 << 25))
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
......@@ -215,28 +207,19 @@ err:
* adreno_ringbuffer_load_pm4_ucode() - Load pm4 ucode
* @device: Pointer to a KGSL device
* @start: Starting index in pm4 ucode to load
* @end: Ending index of pm4 ucode to load
* @addr: Address to load the pm4 ucode
*
* Load the pm4 ucode from @start at @addr.
*/
int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device,
unsigned int start, unsigned int addr)
inline int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device,
unsigned int start, unsigned int end, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
if (adreno_dev->pm4_fw == NULL) {
int ret = adreno_ringbuffer_read_pm4_ucode(device);
if (ret)
return ret;
}
KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
adreno_dev->pm4_fw_version);
adreno_writereg(adreno_dev, ADRENO_REG_CP_DEBUG, CP_DEBUG_DEFAULT);
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_RAM_WADDR, addr);
for (i = 1; i < adreno_dev->pm4_fw_size; i++)
for (i = start; i < end; i++)
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_RAM_DATA,
adreno_dev->pm4_fw[i]);
......@@ -278,27 +261,19 @@ err:
* adreno_ringbuffer_load_pfp_ucode() - Load pfp ucode
* @device: Pointer to a KGSL device
* @start: Starting index in pfp ucode to load
* @end: Ending index of pfp ucode to load
* @addr: Address to load the pfp ucode
*
* Load the pfp ucode from @start at @addr.
*/
int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
unsigned int start, unsigned int addr)
inline int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
unsigned int start, unsigned int end, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
if (adreno_dev->pfp_fw == NULL) {
int ret = adreno_ringbuffer_read_pfp_ucode(device);
if (ret)
return ret;
}
KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
adreno_dev->pfp_fw_version);
adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_ADDR, addr);
for (i = 1; i < adreno_dev->pfp_fw_size; i++)
for (i = start; i < end; i++)
adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_DATA,
adreno_dev->pfp_fw[i]);
......@@ -306,19 +281,95 @@ int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
}
/**
* _ringbuffer_start_common() - Ringbuffer start
* _ringbuffer_bootstrap_ucode() - Bootstrap GPU Ucode
* @rb: Pointer to adreno ringbuffer
* @load_jt: If non zero only load Jump tables
*
* Setup ringbuffer for GPU.
* Bootstrap ucode for GPU
* load_jt == 0, bootstrap full microcode
* load_jt == 1, bootstrap jump tables of microcode
*
* For example a bootstrap packet would like below
* Setup a type3 bootstrap packet
* PFP size to bootstrap
* PFP addr to write the PFP data
* PM4 size to bootstrap
* PM4 addr to write the PM4 data
* PFP dwords from microcode to bootstrap
* PM4 size dwords from microcode to bootstrap
*/
int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
static int _ringbuffer_bootstrap_ucode(struct adreno_ringbuffer *rb,
unsigned int load_jt)
{
int status;
unsigned int *cmds, cmds_gpu, bootstrap_size;
int i = 0;
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int pm4_size, pm4_idx, pm4_addr, pfp_size, pfp_idx, pfp_addr;
/* Only bootstrap jump tables of ucode */
if (load_jt) {
pm4_idx = adreno_dev->pm4_jt_idx;
pm4_addr = adreno_dev->pm4_jt_addr;
pfp_idx = adreno_dev->pfp_jt_idx;
pfp_addr = adreno_dev->pfp_jt_addr;
} else {
/* Bootstrap full ucode */
pm4_idx = 1;
pm4_addr = 0;
pfp_idx = 1;
pfp_addr = 0;
}
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
pm4_size = (adreno_dev->pm4_fw_size - pm4_idx);
pfp_size = (adreno_dev->pfp_fw_size - pfp_idx);
/*
* Below set of commands register with PFP that 6f is the
* opcode for bootstrapping
*/
adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_ADDR, 0x200);
adreno_writereg(adreno_dev, ADRENO_REG_CP_PFP_UCODE_DATA, 0x6f0005);
/* clear ME_HALT to start micro engine */
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, 0);
bootstrap_size = (pm4_size + pfp_size + 5);
cmds = adreno_ringbuffer_allocspace(rb, NULL, bootstrap_size);
if (cmds == NULL)
return -ENOMEM;
cmds_gpu = rb->buffer_desc.gpuaddr +
sizeof(uint) * (rb->wptr - bootstrap_size);
/* Construct the packet that bootsraps the ucode */
GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
cp_type3_packet(CP_BOOTSTRAP_UCODE,
(bootstrap_size - 1)));
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, pfp_size);
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, pfp_addr);
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, pm4_size);
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, pm4_addr);
for (i = pfp_idx; i < adreno_dev->pfp_fw_size; i++)
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, adreno_dev->pfp_fw[i]);
for (i = pm4_idx; i < adreno_dev->pm4_fw_size; i++)
GSL_RB_WRITE(rb->device, cmds, cmds_gpu, adreno_dev->pm4_fw[i]);
adreno_ringbuffer_submit(rb);
/* idle device to validate bootstrap */
return adreno_idle(device);
}
/**
* _ringbuffer_setup_common() - Ringbuffer start
* @rb: Pointer to adreno ringbuffer
*
* Setup ringbuffer for GPU.
*/
void _ringbuffer_setup_common(struct adreno_ringbuffer *rb)
{
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
kgsl_sharedmem_set(rb->device, &rb->buffer_desc, 0, 0xAA,
(rb->sizedwords << 2));
......@@ -359,6 +410,19 @@ int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
kgsl_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
rb->wptr = 0;
}
/**
* _ringbuffer_start_common() - Ringbuffer start
* @rb: Pointer to adreno ringbuffer
*
* Start ringbuffer for GPU.
*/
int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
{
int status;
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
/* clear ME_HALT to start micro engine */
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, 0);
......@@ -390,39 +454,99 @@ int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb)
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
/* load the CP ucode */
status = adreno_ringbuffer_load_pm4_ucode(device,
adreno_dev->pm4_jt_idx, adreno_dev->pm4_jt_addr);
if (status != 0)
return status;
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
/* load the prefetch parser ucode */
status = adreno_ringbuffer_load_pfp_ucode(device,
adreno_dev->pfp_jt_idx, adreno_dev->pfp_jt_addr);
if (status != 0)
return status;
_ringbuffer_setup_common(rb);
return _ringbuffer_start_common(rb);
/* If bootstrapping if supported to load jump tables */
if (adreno_bootstrap_ucode(adreno_dev)) {
status = _ringbuffer_bootstrap_ucode(rb, 1);
if (status != 0)
return status;
} else {
/* load the CP jump tables using AHB writes */
status = adreno_ringbuffer_load_pm4_ucode(device,
adreno_dev->pm4_jt_idx, adreno_dev->pm4_fw_size,
adreno_dev->pm4_jt_addr);
if (status != 0)
return status;
/* load the prefetch parser jump tables using AHB writes */
status = adreno_ringbuffer_load_pfp_ucode(device,
adreno_dev->pfp_jt_idx, adreno_dev->pfp_fw_size,
adreno_dev->pfp_jt_addr);
if (status != 0)
return status;
}
status = _ringbuffer_start_common(rb);
return status;
}
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
/**
* adreno_ringbuffer_cold_start() - Ringbuffer cold start
* @rb: Pointer to adreno ringbuffer
*
* Start the ringbuffer from power collapse.
*/
int adreno_ringbuffer_cold_start(struct adreno_ringbuffer *rb)
{
int status;
struct kgsl_device *device = rb->device;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
/* load the CP ucode */
status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1, 0);
if (status != 0)
return status;
_ringbuffer_setup_common(rb);
/* load the prefetch parser ucode */
status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1, 0);
if (status != 0)
return status;
/* If bootstrapping if supported to load ucode */
if (adreno_bootstrap_ucode(adreno_dev)) {
/*
* load first adreno_dev->pm4_bstrp_size +
* adreno_dev->pfp_bstrp_size microcode dwords using AHB write,
* this small microcode has dispatcher + booter, this initial
* microcode enables CP to understand CP_BOOTSTRAP_UCODE packet
* in function _ringbuffer_bootstrap_ucode. CP_BOOTSTRAP_UCODE
* packet loads rest of the microcode.
*/
status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1,
adreno_dev->pm4_bstrp_size+1, 0);
if (status != 0)
return status;
status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1,
adreno_dev->pfp_bstrp_size+1, 0);
if (status != 0)
return status;
/* Bootstrap rest of the ucode here */
status = _ringbuffer_bootstrap_ucode(rb, 0);
if (status != 0)
return status;
} else {
/* load the CP ucode using AHB writes */
status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1,
adreno_dev->pm4_fw_size, 0);
if (status != 0)
return status;
/* load the prefetch parser ucode using AHB writes */
status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1,
adreno_dev->pfp_fw_size, 0);
if (status != 0)
return status;
}
return _ringbuffer_start_common(rb);
status = _ringbuffer_start_common(rb);
return status;
}
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
......@@ -545,6 +669,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
if (adreno_is_a20x(adreno_dev))
total_sizedwords += 2; /* CACHE_FLUSH */
if (drawctxt) {
total_sizedwords += 3; /* global timestamp without cache
* flush for non-zero context */
......@@ -660,7 +787,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp)));
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb->global_ts);
GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
rb->global_ts);
}
if (adreno_is_a20x(adreno_dev)) {
......@@ -965,7 +1093,7 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
timestamp);
if (ret)
KGSL_DRV_ERR(device, "adreno_dispatcher_queue_cmd returned %d\n",
KGSL_DRV_ERR(device, "adreno_context_queue_cmd returned %d\n",
ret);
else {
/*
......@@ -984,6 +1112,13 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
}
}
/*
* Return -EPROTO if the device has faulted since the last time we
* checked - userspace uses this to perform post-fault activities
*/
if (!ret && test_and_clear_bit(ADRENO_CONTEXT_FAULT, &drawctxt->priv))
ret = -EPROTO;
return ret;
}
......@@ -1017,14 +1152,12 @@ void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
{
unsigned int constraint;
struct kgsl_context *context = cmdbatch->context;
struct adreno_context *drawctxt;
drawctxt = ADRENO_CONTEXT(context);
/*
* Check if the context has a constraint and constraint flags are
* set.
*/
if (context->pwr_constraint.type &&
((drawctxt->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
(cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
constraint = adreno_ringbuffer_get_constraint(device, context);
......@@ -1076,7 +1209,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
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) &&
if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) &&
!test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
(adreno_dev->drawctxt_active == drawctxt))
start_index = 1;
......@@ -1181,7 +1314,7 @@ done:
device->pwrctrl.irq_last = 0;
kgsl_trace_issueibcmds(device, context->id, cmdbatch,
cmdbatch->timestamp, cmdbatch->flags, ret,
drawctxt ? drawctxt->type : 0);
drawctxt->type);
kfree(link);
return ret;
......
......@@ -73,7 +73,7 @@ int adreno_ringbuffer_init(struct kgsl_device *device);
int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb);
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
int adreno_ringbuffer_cold_start(struct adreno_ringbuffer *rb);
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
......
......@@ -20,7 +20,6 @@
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/dma-buf.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include <linux/genlock.h>
......@@ -41,6 +40,7 @@
#include "kgsl_device.h"
#include "kgsl_trace.h"
#include "kgsl_sync.h"
#include "adreno.h"
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "kgsl."
......@@ -513,31 +513,29 @@ EXPORT_SYMBOL(kgsl_context_init);
*/
int kgsl_context_detach(struct kgsl_context *context)
{
struct kgsl_device *device;
int ret;
if (context == NULL || kgsl_context_detached(context))
if (context == NULL)
return -EINVAL;
device = context->device;
trace_kgsl_context_detach(device, context);
/*
* Mark the context as detached to keep others from using
* the context before it gets fully removed
* the context before it gets fully removed, and to make sure
* we don't try to detach twice.
*/
set_bit(KGSL_CONTEXT_DETACHED, &context->priv);
if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
return -EINVAL;
trace_kgsl_context_detach(context->device, context);
ret = device->ftbl->drawctxt_detach(context);
ret = context->device->ftbl->drawctxt_detach(context);
/*
* Cancel events after the device-specific context is
* detached, to avoid possibly freeing memory while
* it is still in use by the GPU.
*/
kgsl_context_cancel_events(device, context);
kgsl_context_cancel_events(context->device, context);
kgsl_context_put(context);
......@@ -842,7 +840,7 @@ kgsl_process_private_put(struct kgsl_process_private *private)
return;
}
/*
/**
* find_process_private() - Helper function to search for process private
* @cur_dev_priv: Pointer to device private structure which contains pointers
* to device and process_private structs.
......@@ -883,7 +881,7 @@ done:
return private;
}
/*
/**
* kgsl_get_process_private() - Used to find the process private structure
* @cur_dev_priv: Current device pointer
* Finds or creates a new porcess private structire and initializes its members
......@@ -897,13 +895,12 @@ kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
private = kgsl_find_process_private(cur_dev_priv);
if (!private)
return NULL;
mutex_lock(&private->process_private_mutex);
/*
* If debug root initialized then it means the rest of the fields
* are also initialized
*/
if (private->debug_root)
if (test_bit(KGSL_PROCESS_INIT, &private->priv))
goto done;
private->mem_rb = RB_ROOT;
......@@ -924,6 +921,8 @@ kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
if (kgsl_process_init_debugfs(private))
goto error;
set_bit(KGSL_PROCESS_INIT, &private->priv);
done:
mutex_unlock(&private->process_private_mutex);
return private;
......@@ -1027,6 +1026,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
result = kgsl_close_device(device);
mutex_unlock(&device->mutex);
kfree(dev_priv);
kgsl_process_private_put(private);
......@@ -1305,10 +1305,12 @@ kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
static inline bool kgsl_mem_entry_set_pend(struct kgsl_mem_entry *entry)
{
bool ret = false;
if (entry == NULL)
return false;
spin_lock(&entry->priv->mem_lock);
if (entry && entry->pending_free) {
ret = false;
} else if (entry) {
if (!entry->pending_free) {
entry->pending_free = 1;
ret = true;
}
......@@ -1363,6 +1365,7 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
result = -EINVAL;
break;
}
/*
* Copy the reset status to value which also serves as
* the out parameter
......@@ -1931,7 +1934,8 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
/**
* _kgsl_cmdbatch_verify() - Perform a quick sanity check on a command batch
* @device: Pointer to a KGSL device that owns the command batch
* @device: Pointer to a KGSL instance that owns the command batch
* @pagetable: Pointer to the pagetable for the current process
* @cmdbatch: Number of indirect buffers to make room for in the cmdbatch
*
* Do a quick sanity test on the list of indirect buffers in a command batch
......@@ -1941,7 +1945,6 @@ static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv,
struct kgsl_cmdbatch *cmdbatch)
{
int i;
struct kgsl_process_private *private = dev_priv->process_priv;
for (i = 0; i < cmdbatch->ibcount; i++) {
......@@ -2106,7 +2109,11 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
cmdbatch, &param->timestamp);
free_cmdbatch:
if (result)
/*
* -EPROTO is a "success" error - it just tells the user that the
* context had previously faulted
*/
if (result && result != -EPROTO)
kgsl_cmdbatch_destroy(cmdbatch);
done:
......@@ -2154,7 +2161,11 @@ static long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
cmdbatch, &param->timestamp);
free_cmdbatch:
if (result)
/*
* -EPROTO is a "success" error - it just tells the user that the
* context had previously faulted
*/
if (result && result != -EPROTO)
kgsl_cmdbatch_destroy(cmdbatch);
done:
......@@ -2363,6 +2374,11 @@ static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
trace_kgsl_mem_free(entry);
kgsl_memfree_hist_set_event(entry->priv->pid,
entry->memdesc.gpuaddr,
entry->memdesc.size,
entry->memdesc.flags);
/*
* First kgsl_mem_entry_put is for the reference that we took in
* this function when calling kgsl_sharedmem_find_id, second one is
......@@ -2445,10 +2461,8 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry,
ret = -ERANGE;
if (phys == 0) {
KGSL_CORE_ERR("kgsl_get_phys_file returned phys=0\n");
if (phys == 0)
goto err;
}
/* Make sure the length of the region, the offset and the desired
* size are all page aligned or bail
......@@ -2456,19 +2470,13 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry,
if ((len & ~PAGE_MASK) ||
(offset & ~PAGE_MASK) ||
(size & ~PAGE_MASK)) {
KGSL_CORE_ERR("length %lu, offset %u or size %u "
"is not page aligned\n",
len, offset, size);
KGSL_CORE_ERR("length offset or size is not page aligned\n");
goto err;
}
/* The size or offset can never be greater than the PMEM length */
if (offset >= len || size > len) {
KGSL_CORE_ERR("offset %u or size %u "
"exceeds pmem length %lu\n",
offset, size, len);
if (offset >= len || size > len)
goto err;
}
/* If size is 0, then adjust it to default to the size of the region
* minus the offset. If size isn't zero, then make sure that it will
......@@ -3104,7 +3112,8 @@ _gpumem_alloc(struct kgsl_device_private *dev_priv,
align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
if (align >= 32) {
KGSL_CORE_ERR("Alignment too big, restricting to 2^32\n");
KGSL_CORE_ERR("Alignment too big, restricting to 2^31\n");
flags &= ~KGSL_MEMALIGN_MASK;
flags |= (31 << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
}
......@@ -3275,11 +3284,12 @@ 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
* 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
* @type: Type of event that signaled the callback
*
* Release a genlock lock following the expiration of a timestamp
*/
......@@ -3400,7 +3410,7 @@ typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *,
static const struct {
unsigned int cmd;
kgsl_ioctl_func_t func;
int flags;
unsigned int flags;
} kgsl_ioctl_funcs[] = {
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
kgsl_ioctl_device_getproperty,
......@@ -3679,7 +3689,7 @@ err_put:
static inline bool
mmap_range_valid(unsigned long addr, unsigned long len)
{
return (addr + len) > addr && (addr + len) < TASK_SIZE;
return ((ULONG_MAX - addr) > len) && ((addr + len) < TASK_SIZE);
}
static unsigned long
......@@ -4163,7 +4173,7 @@ int kgsl_postmortem_dump(struct kgsl_device *device, int manual)
pwr->power_flags, pwr->active_pwrlevel);
KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
pwr->interval_timeout);
pwr->interval_timeout);
}
......
......@@ -272,7 +272,7 @@ static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
size = 1;
/* don't overflow */
if ((gpuaddr + size) < gpuaddr)
if (size > UINT_MAX - gpuaddr)
return 0;
if (gpuaddr >= memdesc->gpuaddr &&
......
/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2008-2011,2013, The Linux Foundation. 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
......@@ -35,7 +35,7 @@ static inline void kgsl_core_debugfs_init(void) { }
static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
static inline void kgsl_core_debugfs_close(void) { }
static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv)
{
return 0;
}
......
......@@ -311,7 +311,6 @@ struct kgsl_device {
};
void kgsl_process_events(struct work_struct *work);
void kgsl_check_fences(struct work_struct *work);
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
......@@ -359,6 +358,7 @@ struct kgsl_process_private;
* @pagefault: flag set if this context caused a pagefault.
* @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT
* is set.
* @flags: flags from userspace controlling the behavior of this context
* @fault_count: number of times gpu hanged in last _context_throttle_time ms
* @fault_time: time of the first gpu hang in last _context_throttle_time ms
* @pwr_constraint: power constraint from userspace for this context
......@@ -377,13 +377,29 @@ struct kgsl_context {
struct list_head events;
struct list_head events_list;
unsigned int pagefault_ts;
unsigned int flags;
unsigned int fault_count;
unsigned long fault_time;
struct kgsl_pwr_constraint pwr_constraint;
};
/**
* struct kgsl_process_private - Private structure for a KGSL process (across
* all devices)
* @priv: Internal flags, use KGSL_PROCESS_* values
* @pid: ID for the task owner of the process
* @mem_lock: Spinlock to protect the process memory lists
* @refcount: kref object for reference counting the process
* @process_private_mutex: Mutex to synchronize access to the process struct
* @mem_rb: RB tree node for the memory owned by this process
* @idr: Iterator for assigning IDs to memory allocations
* @pagetable: Pointer to the pagetable owned by this process
* @kobj: Pointer to a kobj for the sysfs directory for this process
* @debug_root: Pointer to the debugfs root for this process
* @stats: Memory allocation statistics for this process
*/
struct kgsl_process_private {
unsigned int refcnt;
unsigned long priv;
pid_t pid;
spinlock_t mem_lock;
......@@ -405,6 +421,14 @@ struct kgsl_process_private {
} stats[KGSL_MEM_ENTRY_MAX];
};
/**
* enum kgsl_process_priv_flags - Private flags for kgsl_process_private
* @KGSL_PROCESS_INIT: Set if the process structure has been set up
*/
enum kgsl_process_priv_flags {
KGSL_PROCESS_INIT = 0,
};
struct kgsl_device_private {
struct kgsl_device *device;
struct kgsl_process_private *process_priv;
......@@ -637,7 +661,7 @@ static inline int _kgsl_context_get(struct kgsl_context *context)
* Find the context associated with the given ID number, increase the reference
* count on it and return it. The caller must make sure that this call is
* paired with a kgsl_context_put. This function validates that the context id
* given is owned by the dev_priv instancet that is passed in. see
* given is owned by the dev_priv instancet that is passed in. See
* kgsl_context_get for the internal version that doesn't do the check
*/
static inline struct kgsl_context *kgsl_context_get_owner(
......@@ -724,7 +748,16 @@ static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch)
*/
static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
{
return list_empty(&cmdbatch->synclist) ? 0 : 1;
int ret;
if (cmdbatch == NULL)
return 0;
spin_lock(&cmdbatch->lock);
ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
spin_unlock(&cmdbatch->lock);
return ret;
}
#if defined(CONFIG_GPU_TRACEPOINTS)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment