From 16356049f5a3c1630b8da645226ef3f7e7ae4529 Mon Sep 17 00:00:00 2001 From: Jeff Boody <jboody@codeaurora.org> Date: Thu, 10 Jul 2014 13:46:02 -0600 Subject: [PATCH] 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: Jeff Boody <jboody@codeaurora.org> --- drivers/gpu/msm/Makefile | 2 +- drivers/gpu/msm/a2xx_reg.h | 10 +- drivers/gpu/msm/adreno.c | 53 +++-- drivers/gpu/msm/adreno.h | 42 +++- drivers/gpu/msm/adreno_a2xx.c | 49 ++-- drivers/gpu/msm/adreno_a3xx.c | 43 ++-- drivers/gpu/msm/adreno_a3xx_snapshot.c | 3 - drivers/gpu/msm/adreno_a3xx_trace.h | 4 +- drivers/gpu/msm/adreno_debugfs.c | 39 +--- drivers/gpu/msm/adreno_dispatch.c | 100 ++++++-- drivers/gpu/msm/adreno_drawctxt.c | 35 +-- drivers/gpu/msm/adreno_drawctxt.h | 73 +++--- drivers/gpu/msm/adreno_pm4types.h | 6 +- drivers/gpu/msm/adreno_postmortem.c | 2 + drivers/gpu/msm/adreno_ringbuffer.c | 267 ++++++++++++++++------ drivers/gpu/msm/adreno_ringbuffer.h | 2 +- drivers/gpu/msm/kgsl.c | 102 +++++---- drivers/gpu/msm/kgsl.h | 2 +- drivers/gpu/msm/kgsl_debugfs.h | 4 +- drivers/gpu/msm/kgsl_device.h | 41 +++- drivers/gpu/msm/kgsl_drm.c | 39 +++- drivers/gpu/msm/kgsl_events.c | 10 +- drivers/gpu/msm/kgsl_gpummu.c | 18 +- drivers/gpu/msm/kgsl_iommu.c | 59 +++-- drivers/gpu/msm/kgsl_log.h | 4 +- drivers/gpu/msm/kgsl_mmu.c | 2 +- drivers/gpu/msm/kgsl_mmu.h | 2 +- drivers/gpu/msm/kgsl_pwrctrl.c | 29 +-- drivers/gpu/msm/kgsl_pwrscale_trustzone.c | 8 +- drivers/gpu/msm/kgsl_sharedmem.h | 11 +- drivers/gpu/msm/kgsl_snapshot.c | 2 - drivers/gpu/msm/kgsl_sync.c | 60 +---- drivers/gpu/msm/kgsl_sync.h | 2 - drivers/gpu/msm/z180.c | 3 +- 34 files changed, 684 insertions(+), 444 deletions(-) diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 895235fa6e0..53b7b94b933 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -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 \ diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h index c70c4eb86a4..b2fb99f889b 100644 --- a/drivers/gpu/msm/a2xx_reg.h +++ b/drivers/gpu/msm/a2xx_reg.h @@ -1,4 +1,4 @@ -/* 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 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index c0f7aa62654..70fc17e3321 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -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, ®_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; } diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 52a6c51b1e7..67afda780e0 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -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 diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c index a5987afaad8..e4888c89d7c 100644 --- a/drivers/gpu/msm/adreno_a2xx.c +++ b/drivers/gpu/msm/adreno_a2xx.c @@ -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) diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index cf0e66a6f2b..ee34a1df333 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -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, }; diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c index 79431933ff9..9f5765d1671 100644 --- a/drivers/gpu/msm/adreno_a3xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c @@ -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; diff --git a/drivers/gpu/msm/adreno_a3xx_trace.h b/drivers/gpu/msm/adreno_a3xx_trace.h index d48faf4717f..75156e47274 100644 --- a/drivers/gpu/msm/adreno_a3xx_trace.h +++ b/drivers/gpu/msm/adreno_a3xx_trace.h @@ -1,4 +1,4 @@ -/* 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, diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 12804a358f8..a7d1b7fb5f7 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -1,4 +1,4 @@ -/* 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); } diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 6b3e5902ca7..ddf275c56cc 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -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) { diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 1cd24e5871b..fa03a06cf6c 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -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? */ diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 670b0db49cb..97147c0e40d 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -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); diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index e6ec91df079..37c3c50a6f2 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -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 */ diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c index 2c9b968a198..9e807cbe5a2 100644 --- a/drivers/gpu/msm/adreno_postmortem.c +++ b/drivers/gpu/msm/adreno_postmortem.c @@ -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"}, diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 32dd0149b13..bd5c6095283 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -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; diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index b7169495722..697e113c576 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -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); diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c5e7556e7fc..cdea8ac1fb8 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -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, ¶m->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, ¶m->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); } diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 44be5346ac6..10122786979 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -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 && diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h index b2f137cd4b0..fe9bc768390 100644 --- a/drivers/gpu/msm/kgsl_debugfs.h +++ b/drivers/gpu/msm/kgsl_debugfs.h @@ -1,4 +1,4 @@ -/* 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; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 3d22733772f..b78f2753b04 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -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) diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c index 6402bf4cb31..1fc7467701b 100644 --- a/drivers/gpu/msm/kgsl_drm.c +++ b/drivers/gpu/msm/kgsl_drm.c @@ -224,11 +224,23 @@ kgsl_gem_alloc_memory(struct drm_gem_object *obj) return result; } - result = kgsl_mmu_map(priv->pagetable, &priv->memdesc, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_get_gpuaddr(priv->pagetable, + &priv->memdesc); + if (result) { + DRM_ERROR( + "kgsl_mmu_get_gpuaddr failed. result = %d\n", + result); + ion_free(kgsl_drm_ion_client, + priv->ion_handle); + priv->ion_handle = NULL; + return result; + } + result = kgsl_mmu_map(priv->pagetable, &priv->memdesc); if (result) { DRM_ERROR( "kgsl_mmu_map failed. result = %d\n", result); + kgsl_mmu_put_gpuaddr(priv->pagetable, + &priv->memdesc); ion_free(kgsl_drm_ion_client, priv->ion_handle); priv->ion_handle = NULL; @@ -274,10 +286,17 @@ kgsl_gem_alloc_memory(struct drm_gem_object *obj) priv->memdesc.sglen++; } + result = kgsl_mmu_get_gpuaddr(priv->pagetable, &priv->memdesc); + if (result) { + DRM_ERROR( + "kgsl_mmu_get_gpuaddr failed. result = %d\n", result); + goto memerr; + } result = kgsl_mmu_map(priv->pagetable, &priv->memdesc); if (result) { DRM_ERROR( "kgsl_mmu_map failed. result = %d\n", result); + kgsl_mmu_put_gpuaddr(priv->pagetable, &priv->memdesc); goto memerr; } @@ -312,8 +331,10 @@ kgsl_gem_free_memory(struct drm_gem_object *obj) if (!kgsl_gem_memory_allocated(obj) || TYPE_IS_FD(priv->type)) return; - if (priv->memdesc.gpuaddr) + if (priv->memdesc.gpuaddr) { kgsl_mmu_unmap(priv->memdesc.pagetable, &priv->memdesc); + kgsl_mmu_put_gpuaddr(priv->memdesc.pagetable, &priv->memdesc); + } /* ION will take care of freeing the sg table. */ priv->memdesc.sg = NULL; @@ -646,9 +667,21 @@ kgsl_gem_create_from_ion_ioctl(struct drm_device *dev, void *data, priv->memdesc.sglen++; } + ret = kgsl_mmu_get_gpuaddr(priv->pagetable, &priv->memdesc); + if (ret) { + DRM_ERROR("kgsl_mmu_get_gpuaddr failed. ret = %d\n", ret); + ion_free(kgsl_drm_ion_client, + priv->ion_handle); + priv->ion_handle = NULL; + kgsl_mmu_putpagetable(priv->pagetable); + drm_gem_object_release(obj); + kfree(priv); + return -ENOMEM; + } ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc); if (ret) { DRM_ERROR("kgsl_mmu_map failed. ret = %d\n", ret); + kgsl_mmu_put_gpuaddr(priv->pagetable, &priv->memdesc); ion_free(kgsl_drm_ion_client, priv->ion_handle); priv->ion_handle = NULL; diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index d58b844dbba..342d76c6dd0 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -213,7 +213,6 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, struct kgsl_event *event; unsigned int queued = 0, cur_ts; struct kgsl_context *context = NULL; - struct adreno_context *drawctxt = NULL; BUG_ON(!mutex_is_locked(&device->mutex)); @@ -224,7 +223,6 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, context = kgsl_context_get(device, id); if (context == NULL) return -EINVAL; - drawctxt = ADRENO_CONTEXT(context); } /* * If the caller is creating their own timestamps, let them schedule @@ -232,7 +230,7 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, * queued. */ if (context == NULL || - ((drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) == 0)) { + ((context->flags & KGSL_CONTEXT_USER_GENERATED_TS) == 0)) { queued = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED); @@ -340,7 +338,11 @@ void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context, void *priv) { struct kgsl_event *event; - struct list_head *head = _get_list_head(device, context); + struct list_head *head; + + BUG_ON(!mutex_is_locked(&device->mutex)); + + head = _get_list_head(device, context); event = _find_event(device, head, timestamp, func, priv); diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c index 1a1e2e3549f..2634e4f05a2 100644 --- a/drivers/gpu/msm/kgsl_gpummu.c +++ b/drivers/gpu/msm/kgsl_gpummu.c @@ -23,6 +23,7 @@ #include "kgsl_device.h" #include "kgsl_sharedmem.h" #include "kgsl_trace.h" +#include "adreno.h" #define KGSL_PAGETABLE_SIZE \ ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \ @@ -403,11 +404,22 @@ static void kgsl_gpummu_pagefault(struct kgsl_mmu *mmu) { unsigned int reg; unsigned int ptbase; + struct kgsl_device *device; + struct adreno_device *adreno_dev; + unsigned int no_page_fault_log = 0; - kgsl_regread(mmu->device, MH_MMU_PAGE_FAULT, ®); - kgsl_regread(mmu->device, MH_MMU_PT_BASE, &ptbase); + device = mmu->device; + adreno_dev = ADRENO_DEVICE(device); + + kgsl_regread(device, MH_MMU_PAGE_FAULT, ®); + kgsl_regread(device, MH_MMU_PT_BASE, &ptbase); + + + if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE) + no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, reg); - KGSL_MEM_CRIT(mmu->device, + if (!no_page_fault_log) + KGSL_MEM_CRIT(mmu->device, "mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n", reg & ~(PAGE_SIZE - 1), kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index f8b61c78f4b..03a58e9ed1a 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -47,7 +47,7 @@ static struct kgsl_iommu_register_list kgsl_iommuv0_reg[KGSL_IOMMU_REG_MAX] = { { 0x03C, 1 }, /* TLBLKCR */ { 0x818, 1 }, /* V2PUR */ { 0x2C, 1 }, /* FSYNR0 */ - { 0x30, 1 }, /* FSYNR0 */ + { 0x30, 1 }, /* FSYNR1 */ { 0, 0 }, /* TLBSYNC, not in v0 */ { 0, 0 }, /* TLBSTATUS, not in v0 */ { 0, 0 } /* IMPLDEF_MICRO_MMU_CRTL, not in v0 */ @@ -322,13 +322,13 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct kgsl_iommu_unit *iommu_unit; struct kgsl_iommu_device *iommu_dev; unsigned int ptbase, fsr; - struct kgsl_device *device; - struct adreno_device *adreno_dev; - unsigned int no_page_fault_log = 0; unsigned int pid; + struct _mem_entry prev, next; unsigned int fsynr0, fsynr1; int write; - struct _mem_entry prev, next; + struct kgsl_device *device; + struct adreno_device *adreno_dev; + unsigned int no_page_fault_log = 0; unsigned int curr_context_id = 0; unsigned int curr_global_ts = 0; struct kgsl_context *context; @@ -432,6 +432,7 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, _print_entry(iommu_dev->kgsldev, &next); else KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n"); + } trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr, @@ -820,6 +821,7 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id]; int i, j; int found_ctx; + int ret = 0; for (j = 0; j < KGSL_IOMMU_MAX_DEVS_PER_UNIT; j++) { found_ctx = 0; @@ -833,17 +835,22 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, break; if (!data->iommu_ctxs[i].iommu_ctx_name) { KGSL_CORE_ERR("Context name invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto done; } atomic_set(&(iommu_unit->clk_enable_count), 0); iommu_unit->dev[iommu_unit->dev_count].dev = msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name); - if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) { - KGSL_CORE_ERR("Failed to get iommu dev handle for " - "device %s\n", data->iommu_ctxs[i].iommu_ctx_name); - return -EINVAL; + if (NULL == iommu_unit->dev[iommu_unit->dev_count].dev) + ret = -EINVAL; + if (IS_ERR(iommu_unit->dev[iommu_unit->dev_count].dev)) { + ret = PTR_ERR( + iommu_unit->dev[iommu_unit->dev_count].dev); + iommu_unit->dev[iommu_unit->dev_count].dev = NULL; } + if (ret) + goto done; iommu_unit->dev[iommu_unit->dev_count].ctx_id = data->iommu_ctxs[i].ctx_id; iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device; @@ -855,12 +862,23 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, iommu_unit->dev_count++; } - if (!j) { - KGSL_CORE_ERR("No ctxts initialized, user ctxt absent\n "); - return -EINVAL; +done: + if (!iommu_unit->dev_count && !ret) + ret = -EINVAL; + if (ret) { + /* + * If at least the first context is initialized on v1 + * then we can continue + */ + if (!msm_soc_version_supports_iommu_v1() && + iommu_unit->dev_count) + ret = 0; + else + KGSL_CORE_ERR( + "Failed to initialize iommu contexts, err: %d\n", ret); } - return 0; + return ret; } /* @@ -923,6 +941,17 @@ static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu) !kgsl_mmu_is_perprocess(mmu)) return status; + /* + * For 2D devices cpu side sync lock is required. For 3D device, + * since we only have a single 3D core and we always ensure that + * 3D core is idle while writing to IOMMU register using CPU this + * lock is not required + */ + if (KGSL_DEVICE_2D0 == mmu->device->id || + KGSL_DEVICE_2D1 == mmu->device->id) { + return status; + } + /* Return if already initialized */ if (iommu->sync_lock_initialized) return status; @@ -1915,7 +1944,7 @@ static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu, int temp; int i; int ret = 0; - unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu, + phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu, mmu->hwpagetable); phys_addr_t pt_val; diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h index 81a35e0d20e..f90627e8dbe 100644 --- a/drivers/gpu/msm/kgsl_log.h +++ b/drivers/gpu/msm/kgsl_log.h @@ -1,4 +1,4 @@ -/* 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 @@ -13,8 +13,6 @@ #ifndef __KGSL_LOG_H #define __KGSL_LOG_H -extern unsigned int kgsl_cff_dump_enable; - #define KGSL_LOG_INFO(dev, lvl, fmt, args...) \ do { \ if ((lvl) >= 6) \ diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 1910a46e995..6b04aadb9a0 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -348,7 +348,7 @@ kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, phys_addr_t pt_base, unsigned int ret = 0; if (!mmu->mmu_ops || !mmu->mmu_ops->mmu_pt_equal) - return KGSL_MMU_GLOBAL_PT; + return 0; spin_lock(&kgsl_driver.ptlock); list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { if (kref_get_unless_zero(&pt->refcount)) { diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index ac4bae36055..5fcc6f4b190 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* 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 diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 80492d71a90..e7eaa93b12a 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -766,12 +766,12 @@ DEVICE_ATTR(thermal_pwrlevel, 0644, DEVICE_ATTR(num_pwrlevels, 0444, kgsl_pwrctrl_num_pwrlevels_show, NULL); -DEVICE_ATTR(reset_count, 0444, - kgsl_pwrctrl_reset_count_show, - NULL); DEVICE_ATTR(pmqos_latency, 0644, kgsl_pwrctrl_pmqos_latency_show, kgsl_pwrctrl_pmqos_latency_store); +DEVICE_ATTR(reset_count, 0444, + kgsl_pwrctrl_reset_count_show, + NULL); DEVICE_ATTR(force_clk_on, 0644, kgsl_pwrctrl_force_clk_on_show, kgsl_pwrctrl_force_clk_on_store); @@ -793,8 +793,8 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_min_pwrlevel, &dev_attr_thermal_pwrlevel, &dev_attr_num_pwrlevels, - &dev_attr_reset_count, &dev_attr_pmqos_latency, + &dev_attr_reset_count, &dev_attr_force_clk_on, &dev_attr_force_bus_on, &dev_attr_force_rail_on, @@ -1381,7 +1381,6 @@ int kgsl_pwrctrl_sleep(struct kgsl_device *device) break; case KGSL_STATE_SLEEP: status = _sleep(device); - kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); break; case KGSL_STATE_SLUMBER: status = _slumber(device); @@ -1432,6 +1431,7 @@ int kgsl_pwrctrl_wake(struct kgsl_device *device) kgsl_pwrstate_to_str(state), context ? context->id : -1, ts_processed); kgsl_context_put(context); + /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ @@ -1538,13 +1538,11 @@ int kgsl_active_count_get(struct kgsl_device *device) int ret = 0; BUG_ON(!mutex_is_locked(&device->mutex)); - if (atomic_read(&device->active_cnt) == 0) { - if (device->requested_state == KGSL_STATE_SUSPEND || - device->state == KGSL_STATE_SUSPEND) { - mutex_unlock(&device->mutex); - wait_for_completion(&device->hwaccess_gate); - mutex_lock(&device->mutex); - } + if ((atomic_read(&device->active_cnt) == 0) && + (device->state != KGSL_STATE_ACTIVE)) { + mutex_unlock(&device->mutex); + wait_for_completion(&device->hwaccess_gate); + mutex_lock(&device->mutex); ret = kgsl_pwrctrl_wake(device); } @@ -1597,12 +1595,9 @@ void kgsl_active_count_put(struct kgsl_device *device) if (atomic_dec_and_test(&device->active_cnt)) { if (device->state == KGSL_STATE_ACTIVE && - device->requested_state == KGSL_STATE_NONE) { + device->requested_state == KGSL_STATE_NONE) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); - if (kgsl_pwrctrl_sleep(device)) { - kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); - queue_work(device->work_queue, &device->idle_check_ws); - } + queue_work(device->work_queue, &device->idle_check_ws); } mod_timer(&device->idle_timer, diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c index 81336638f49..d3ebf24d71e 100644 --- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c +++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c @@ -160,11 +160,13 @@ static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale) (priv->bin.total_time < FLOOR)) return; - /* If there is an extended block of busy processing, - * increase frequency. Otherwise run the normal algorithm. + /* If there is an extended block of busy processing, set + * frequency to turbo. Otherwise run the normal algorithm. */ if (priv->bin.busy_time > CEILING) { - val = -1; + val = 0; + kgsl_pwrctrl_pwrlevel_change(device, + KGSL_PWRLEVEL_TURBO); } else if (priv->idle_dcvs) { idle = priv->bin.total_time - priv->bin.busy_time; idle = (idle > 0) ? idle : 0; diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 4a43d148097..f0114ad195f 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -146,13 +146,8 @@ static inline void *kgsl_sg_alloc(unsigned int sglen) if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE) return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL); - else { - void *ptr = vmalloc(sglen * sizeof(struct scatterlist)); - if (ptr) - memset(ptr, 0, sglen * sizeof(struct scatterlist)); - - return ptr; - } + else + return vmalloc(sglen * sizeof(struct scatterlist)); } static inline void kgsl_sg_free(void *ptr, unsigned int sglen) @@ -168,7 +163,7 @@ memdesc_sg_phys(struct kgsl_memdesc *memdesc, phys_addr_t physaddr, unsigned int size) { memdesc->sg = kgsl_sg_alloc(1); - if (!memdesc->sg) + if (memdesc->sg == NULL) return -ENOMEM; kmemleak_not_leak(memdesc->sg); diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index a81e19c520a..beda17f3169 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -210,10 +210,8 @@ static int snapshot_os(struct kgsl_device *device, header->ctxtcount = ctxtcount; _ctxtptr = snapshot + sizeof(*header); - /* append information for the global context */ snapshot_context_info(KGSL_MEMSTORE_GLOBAL, NULL, device); - /* append information for each context */ read_lock(&device->context_lock); diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 0e7606e842c..dd32e147943 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -13,12 +13,9 @@ #include <linux/err.h> #include <linux/file.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/uaccess.h> -#include <asm/current.h> - #include "kgsl_sync.h" struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline, @@ -90,9 +87,7 @@ static inline void kgsl_fence_event_cb(struct kgsl_device *device, void *priv, u32 context_id, u32 timestamp, u32 type) { struct kgsl_fence_event_priv *ev = priv; - - /* Signal time timeline for every event type */ - kgsl_sync_timeline_signal(ev->context->timeline, timestamp); + kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp); kgsl_context_put(ev->context); kfree(ev); } @@ -130,10 +125,8 @@ int kgsl_add_fence_event(struct kgsl_device *device, context = kgsl_context_get_owner(owner, context_id); - if (context == NULL) { - kfree(event); - return -EINVAL; - } + if (context == NULL) + goto fail_pt; event->context = context; event->timestamp = timestamp; @@ -192,35 +185,6 @@ fail_pt: return ret; } -static unsigned int kgsl_sync_get_timestamp( - struct kgsl_sync_timeline *ktimeline, enum kgsl_timestamp_type type) -{ - struct kgsl_context *context = idr_find(&ktimeline->device->context_idr, - ktimeline->context_id); - if (context == NULL) - return 0; - - return kgsl_readtimestamp(ktimeline->device, context, type); -} - -static void kgsl_sync_timeline_value_str(struct sync_timeline *sync_timeline, - char *str, int size) -{ - struct kgsl_sync_timeline *ktimeline = - (struct kgsl_sync_timeline *) sync_timeline; - unsigned int timestamp_retired = kgsl_sync_get_timestamp(ktimeline, - KGSL_TIMESTAMP_RETIRED); - snprintf(str, size, "%u retired:%u", ktimeline->last_timestamp, - timestamp_retired); -} - -static void kgsl_sync_pt_value_str(struct sync_pt *sync_pt, - char *str, int size) -{ - struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) sync_pt; - snprintf(str, size, "%u", kpt->timestamp); -} - static void kgsl_sync_timeline_release_obj(struct sync_timeline *sync_timeline) { /* @@ -235,8 +199,6 @@ static const struct sync_timeline_ops kgsl_sync_timeline_ops = { .dup = kgsl_sync_pt_dup, .has_signaled = kgsl_sync_pt_has_signaled, .compare = kgsl_sync_pt_compare, - .timeline_value_str = kgsl_sync_timeline_value_str, - .pt_value_str = kgsl_sync_pt_value_str, .release_obj = kgsl_sync_timeline_release_obj, }; @@ -244,25 +206,13 @@ int kgsl_sync_timeline_create(struct kgsl_context *context) { struct kgsl_sync_timeline *ktimeline; - /* Generate a name which includes the thread name, thread id, process - * name, process id, and context id. This makes it possible to - * identify the context of a timeline in the sync dump. */ - char ktimeline_name[sizeof(context->timeline->name)] = {}; - snprintf(ktimeline_name, sizeof(ktimeline_name), - "%s_%.15s(%d)-%.15s(%d)-%d", - context->device->name, - current->group_leader->comm, current->group_leader->pid, - current->comm, current->pid, context->id); - context->timeline = sync_timeline_create(&kgsl_sync_timeline_ops, - (int) sizeof(struct kgsl_sync_timeline), ktimeline_name); + (int) sizeof(struct kgsl_sync_timeline), "kgsl-timeline"); if (context->timeline == NULL) return -EINVAL; ktimeline = (struct kgsl_sync_timeline *) context->timeline; ktimeline->last_timestamp = 0; - ktimeline->device = context->dev_priv->device; - ktimeline->context_id = context->id; return 0; } @@ -305,7 +255,7 @@ struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd, return ERR_PTR(-EINVAL); /* create the waiter */ - kwaiter = kzalloc(sizeof(*kwaiter), GFP_KERNEL); + kwaiter = kzalloc(sizeof(*kwaiter), GFP_ATOMIC); if (kwaiter == NULL) { sync_fence_put(fence); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h index 275eaf07dfb..2f28b21fc6d 100644 --- a/drivers/gpu/msm/kgsl_sync.h +++ b/drivers/gpu/msm/kgsl_sync.h @@ -19,8 +19,6 @@ struct kgsl_sync_timeline { struct sync_timeline timeline; unsigned int last_timestamp; - struct kgsl_device *device; - u32 context_id; }; struct kgsl_sync_pt { diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c index 45f200c3454..ae7aee0a0f5 100644 --- a/drivers/gpu/msm/z180.c +++ b/drivers/gpu/msm/z180.c @@ -514,7 +514,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0); error: kgsl_trace_issueibcmds(device, context->id, cmdbatch, - *timestamp, cmdbatch->flags, result, 0); + *timestamp, cmdbatch ? cmdbatch->flags : 0, result, 0); kgsl_active_count_put(device); error_active_count: @@ -614,7 +614,6 @@ static int z180_start(struct kgsl_device *device) z180_cmdstream_start(device); - mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); device->ftbl->irqctrl(device, 1); -- GitLab