diff options
Diffstat (limited to 'drivers/gpu/drm/msm/adreno')
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 242 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_device.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.c | 187 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.h | 11 |
6 files changed, 452 insertions, 54 deletions
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 3ebbeb3a9b68..669c2d4b070d 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -411,15 +411,6 @@ static const unsigned int a3xx_registers[] = { ~0 /* sentinel */ }; -#ifdef CONFIG_DEBUG_FS -static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) -{ - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A3XX_RBBM_STATUS)); - adreno_show(gpu, m); -} -#endif - /* would be nice to not have to duplicate the _show() stuff with printk(): */ static void a3xx_dump(struct msm_gpu *gpu) { @@ -427,6 +418,21 @@ static void a3xx_dump(struct msm_gpu *gpu) gpu_read(gpu, REG_A3XX_RBBM_STATUS)); adreno_dump(gpu); } + +static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu) +{ + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); + + state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); + + return state; +} + /* Register offset defines for A3XX */ static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE), @@ -450,9 +456,11 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = adreno_active_ring, .irq = a3xx_irq, .destroy = a3xx_destroy, -#ifdef CONFIG_DEBUG_FS - .show = a3xx_show, +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) + .show = adreno_show, #endif + .gpu_state_get = a3xx_gpu_state_get, + .gpu_state_put = adreno_gpu_state_put, }, }; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 16d3d596638e..7c4e6dc1ed59 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -455,15 +455,19 @@ static const unsigned int a4xx_registers[] = { ~0 /* sentinel */ }; -#ifdef CONFIG_DEBUG_FS -static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) +static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) { - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A4XX_RBBM_STATUS)); - adreno_show(gpu, m); + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); + state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS); + + return state; } -#endif /* Register offset defines for A4XX, in order of enum adreno_regs */ static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { @@ -538,9 +542,11 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = adreno_active_ring, .irq = a4xx_irq, .destroy = a4xx_destroy, -#ifdef CONFIG_DEBUG_FS - .show = a4xx_show, +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) + .show = adreno_show, #endif + .gpu_state_get = a4xx_gpu_state_get, + .gpu_state_put = adreno_gpu_state_put, }, .get_timestamp = a4xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index d39400e5bc42..bd84f71d27d8 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -19,6 +19,7 @@ #include <linux/soc/qcom/mdt_loader.h> #include <linux/pm_opp.h> #include <linux/nvmem-consumer.h> +#include <linux/iopoll.h> #include "msm_gem.h" #include "msm_mmu.h" #include "a5xx_gpu.h" @@ -1123,8 +1124,9 @@ static const u32 a5xx_registers[] = { 0xE800, 0xE806, 0xE810, 0xE89A, 0xE8A0, 0xE8A4, 0xE8AA, 0xE8EB, 0xE900, 0xE905, 0xEB80, 0xEB8F, 0xEBB0, 0xEBB0, 0xEC00, 0xEC05, 0xEC08, 0xECE9, 0xECF0, 0xECF0, 0xEA80, 0xEA80, 0xEA82, 0xEAA3, - 0xEAA5, 0xEAC2, 0xA800, 0xA8FF, 0xAC60, 0xAC60, 0xB000, 0xB97F, - 0xB9A0, 0xB9BF, ~0 + 0xEAA5, 0xEAC2, 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D, + 0XA880, 0xA88D, 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5, + 0xAC60, 0xAC60, ~0, }; static void a5xx_dump(struct msm_gpu *gpu) @@ -1195,19 +1197,231 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) return 0; } -#ifdef CONFIG_DEBUG_FS -static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) +struct a5xx_crashdumper { + void *ptr; + struct drm_gem_object *bo; + u64 iova; +}; + +struct a5xx_gpu_state { + struct msm_gpu_state base; + u32 *hlsqregs; +}; + +#define gpu_poll_timeout(gpu, addr, val, cond, interval, timeout) \ + readl_poll_timeout((gpu)->mmio + ((addr) << 2), val, cond, \ + interval, timeout) + +static int a5xx_crashdumper_init(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) { - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A5XX_RBBM_STATUS)); + dumper->ptr = msm_gem_kernel_new_locked(gpu->dev, + SZ_1M, MSM_BO_UNCACHED, gpu->aspace, + &dumper->bo, &dumper->iova); - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ + if (IS_ERR(dumper->ptr)) + return PTR_ERR(dumper->ptr); + + return 0; +} + +static void a5xx_crashdumper_free(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) +{ + msm_gem_put_iova(dumper->bo, gpu->aspace); + msm_gem_put_vaddr(dumper->bo); + + drm_gem_object_unreference(dumper->bo); +} + +static int a5xx_crashdumper_run(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) +{ + u32 val; + + if (IS_ERR_OR_NULL(dumper->ptr)) + return -EINVAL; + + gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, + REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova); + + gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); + + return gpu_poll_timeout(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, val, + val & 0x04, 100, 10000); +} + +/* + * These are a list of the registers that need to be read through the HLSQ + * aperture through the crashdumper. These are not nominally accessible from + * the CPU on a secure platform. + */ +static const struct { + u32 type; + u32 regoffset; + u32 count; +} a5xx_hlsq_aperture_regs[] = { + { 0x35, 0xe00, 0x32 }, /* HSLQ non-context */ + { 0x31, 0x2080, 0x1 }, /* HLSQ 2D context 0 */ + { 0x33, 0x2480, 0x1 }, /* HLSQ 2D context 1 */ + { 0x32, 0xe780, 0x62 }, /* HLSQ 3D context 0 */ + { 0x34, 0xef80, 0x62 }, /* HLSQ 3D context 1 */ + { 0x3f, 0x0ec0, 0x40 }, /* SP non-context */ + { 0x3d, 0x2040, 0x1 }, /* SP 2D context 0 */ + { 0x3b, 0x2440, 0x1 }, /* SP 2D context 1 */ + { 0x3e, 0xe580, 0x170 }, /* SP 3D context 0 */ + { 0x3c, 0xed80, 0x170 }, /* SP 3D context 1 */ + { 0x3a, 0x0f00, 0x1c }, /* TP non-context */ + { 0x38, 0x2000, 0xa }, /* TP 2D context 0 */ + { 0x36, 0x2400, 0xa }, /* TP 2D context 1 */ + { 0x39, 0xe700, 0x80 }, /* TP 3D context 0 */ + { 0x37, 0xef00, 0x80 }, /* TP 3D context 1 */ +}; + +static void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu, + struct a5xx_gpu_state *a5xx_state) +{ + struct a5xx_crashdumper dumper = { 0 }; + u32 offset, count = 0; + u64 *ptr; + int i; + + if (a5xx_crashdumper_init(gpu, &dumper)) + return; + + /* The script will be written at offset 0 */ + ptr = dumper.ptr; + + /* Start writing the data at offset 256k */ + offset = dumper.iova + (256 * SZ_1K); + + /* Count how many additional registers to get from the HLSQ aperture */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) + count += a5xx_hlsq_aperture_regs[i].count; + + a5xx_state->hlsqregs = kcalloc(count, sizeof(u32), GFP_KERNEL); + if (!a5xx_state->hlsqregs) + return; + + /* Build the crashdump script */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { + u32 type = a5xx_hlsq_aperture_regs[i].type; + u32 c = a5xx_hlsq_aperture_regs[i].count; + + /* Write the register to select the desired bank */ + *ptr++ = ((u64) type << 8); + *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_READ_SEL) << 44) | + (1 << 21) | 1; + + *ptr++ = offset; + *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE) << 44) + | c; + + offset += c * sizeof(u32); + } + + /* Write two zeros to close off the script */ + *ptr++ = 0; + *ptr++ = 0; + + if (a5xx_crashdumper_run(gpu, &dumper)) { + kfree(a5xx_state->hlsqregs); + a5xx_crashdumper_free(gpu, &dumper); + return; + } + + /* Copy the data from the crashdumper to the state */ + memcpy(a5xx_state->hlsqregs, dumper.ptr + (256 * SZ_1K), + count * sizeof(u32)); + + a5xx_crashdumper_free(gpu, &dumper); +} + +static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) +{ + struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), + GFP_KERNEL); + + if (!a5xx_state) + return ERR_PTR(-ENOMEM); + + /* Temporarily disable hardware clock gating before reading the hw */ a5xx_set_hwcg(gpu, false); - adreno_show(gpu, m); + + /* First get the generic state from the adreno core */ + adreno_gpu_state_get(gpu, &(a5xx_state->base)); + + a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); + + /* Get the HLSQ regs with the help of the crashdumper */ + a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); + a5xx_set_hwcg(gpu, true); + + return &a5xx_state->base; +} + +static void a5xx_gpu_state_destroy(struct kref *kref) +{ + struct msm_gpu_state *state = container_of(kref, + struct msm_gpu_state, ref); + struct a5xx_gpu_state *a5xx_state = container_of(state, + struct a5xx_gpu_state, base); + + kfree(a5xx_state->hlsqregs); + + adreno_gpu_state_destroy(state); + kfree(a5xx_state); +} + +int a5xx_gpu_state_put(struct msm_gpu_state *state) +{ + if (IS_ERR_OR_NULL(state)) + return 1; + + return kref_put(&state->ref, a5xx_gpu_state_destroy); +} + + +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) +void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct drm_printer *p) +{ + int i, j; + u32 pos = 0; + struct a5xx_gpu_state *a5xx_state = container_of(state, + struct a5xx_gpu_state, base); + + if (IS_ERR_OR_NULL(state)) + return; + + adreno_show(gpu, state, p); + + /* Dump the additional a5xx HLSQ registers */ + if (!a5xx_state->hlsqregs) + return; + + drm_printf(p, "registers-hlsq:\n"); + + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { + u32 o = a5xx_hlsq_aperture_regs[i].regoffset; + u32 c = a5xx_hlsq_aperture_regs[i].count; + + for (j = 0; j < c; j++, pos++, o++) { + /* + * To keep the crashdump simple we pull the entire range + * for each register type but not all of the registers + * in the range are valid. Fortunately invalid registers + * stick out like a sore thumb with a value of + * 0xdeadbeef + */ + if (a5xx_state->hlsqregs[pos] == 0xdeadbeef) + continue; + + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", + o << 2, a5xx_state->hlsqregs[pos]); + } + } } #endif @@ -1239,11 +1453,15 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = a5xx_active_ring, .irq = a5xx_irq, .destroy = a5xx_destroy, -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) .show = a5xx_show, +#endif +#if defined(CONFIG_DEBUG_FS) .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, + .gpu_state_get = a5xx_gpu_state_get, + .gpu_state_put = a5xx_gpu_state_put, }, .get_timestamp = a5xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 0ae5ace65462..44813624a286 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -35,6 +35,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_256K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 0, 6, 0), @@ -45,6 +46,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_128K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), @@ -55,6 +57,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_512K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 3, 0, ANY_ID), @@ -65,6 +68,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a330_pfp.fw", }, .gmem = SZ_1M, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(4, 2, 0, ANY_ID), @@ -75,6 +79,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a420_pfp.fw", }, .gmem = (SZ_1M + SZ_512K), + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(4, 3, 0, ANY_ID), @@ -85,6 +90,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a420_pfp.fw", }, .gmem = (SZ_1M + SZ_512K), + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(5, 3, 0, 2), @@ -96,6 +102,11 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_GPMU] = "a530v3_gpmu.fw2", }, .gmem = SZ_1M, + /* + * Increase inactive period to 250 to avoid bouncing + * the GDSC which appears to make it grumpy + */ + .inactive_period = 250, .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | ADRENO_QUIRK_FAULT_DETECT_MASK, .init = a5xx_gpu_init, @@ -158,7 +169,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) mutex_lock(&dev->struct_mutex); ret = msm_gpu_hw_init(gpu); mutex_unlock(&dev->struct_mutex); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); return NULL; @@ -316,6 +327,7 @@ static int adreno_suspend(struct device *dev) #endif static const struct dev_pm_ops adreno_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL) }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 17d0506d058c..38ac50b73829 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -17,6 +17,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/ascii85.h> #include <linux/pm_opp.h> #include "adreno_gpu.h" #include "msm_gem.h" @@ -368,40 +369,185 @@ bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) return false; } -#ifdef CONFIG_DEBUG_FS -void adreno_show(struct msm_gpu *gpu, struct seq_file *m) +int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + int i, count = 0; + + kref_init(&state->ref); + + ktime_get_real_ts64(&state->time); + + for (i = 0; i < gpu->nr_rings; i++) { + int size = 0, j; + + state->ring[i].fence = gpu->rb[i]->memptrs->fence; + state->ring[i].iova = gpu->rb[i]->iova; + state->ring[i].seqno = gpu->rb[i]->seqno; + state->ring[i].rptr = get_rptr(adreno_gpu, gpu->rb[i]); + state->ring[i].wptr = get_wptr(gpu->rb[i]); + + /* Copy at least 'wptr' dwords of the data */ + size = state->ring[i].wptr; + + /* After wptr find the last non zero dword to save space */ + for (j = state->ring[i].wptr; j < MSM_GPU_RINGBUFFER_SZ >> 2; j++) + if (gpu->rb[i]->start[j]) + size = j + 1; + + if (size) { + state->ring[i].data = kmalloc(size << 2, GFP_KERNEL); + if (state->ring[i].data) { + memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2); + state->ring[i].data_size = size << 2; + } + } + } + + /* Count the number of registers */ + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) + count += adreno_gpu->registers[i + 1] - + adreno_gpu->registers[i] + 1; + + state->registers = kcalloc(count * 2, sizeof(u32), GFP_KERNEL); + if (state->registers) { + int pos = 0; + + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { + u32 start = adreno_gpu->registers[i]; + u32 end = adreno_gpu->registers[i + 1]; + u32 addr; + + for (addr = start; addr <= end; addr++) { + state->registers[pos++] = addr; + state->registers[pos++] = gpu_read(gpu, addr); + } + } + + state->nr_registers = count; + } + + return 0; +} + +void adreno_gpu_state_destroy(struct msm_gpu_state *state) +{ int i; - seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", + for (i = 0; i < ARRAY_SIZE(state->ring); i++) + kfree(state->ring[i].data); + + for (i = 0; state->bos && i < state->nr_bos; i++) + kvfree(state->bos[i].data); + + kfree(state->bos); + kfree(state->comm); + kfree(state->cmd); + kfree(state->registers); +} + +static void adreno_gpu_state_kref_destroy(struct kref *kref) +{ + struct msm_gpu_state *state = container_of(kref, + struct msm_gpu_state, ref); + + adreno_gpu_state_destroy(state); + kfree(state); +} + +int adreno_gpu_state_put(struct msm_gpu_state *state) +{ + if (IS_ERR_OR_NULL(state)) + return 1; + + return kref_put(&state->ref, adreno_gpu_state_kref_destroy); +} + +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) + +static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) +{ + char out[ASCII85_BUFSZ]; + long l, datalen, i; + + if (!ptr || !len) + return; + + /* + * Only dump the non-zero part of the buffer - rarely will any data + * completely fill the entire allocated size of the buffer + */ + for (datalen = 0, i = 0; i < len >> 2; i++) { + if (ptr[i]) + datalen = (i << 2) + 1; + } + + /* Skip printing the object if it is empty */ + if (datalen == 0) + return; + + l = ascii85_encode_len(datalen); + + drm_puts(p, " data: !!ascii85 |\n"); + drm_puts(p, " "); + + for (i = 0; i < l; i++) + drm_puts(p, ascii85_encode(ptr[i], out)); + + drm_puts(p, "\n"); +} + +void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct drm_printer *p) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + int i; + + if (IS_ERR_OR_NULL(state)) + return; + + drm_printf(p, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); - for (i = 0; i < gpu->nr_rings; i++) { - struct msm_ringbuffer *ring = gpu->rb[i]; + drm_printf(p, "rbbm-status: 0x%08x\n", state->rbbm_status); - seq_printf(m, "rb %d: fence: %d/%d\n", i, - ring->memptrs->fence, ring->seqno); + drm_puts(p, "ringbuffer:\n"); - seq_printf(m, " rptr: %d\n", - get_rptr(adreno_gpu, ring)); - seq_printf(m, "rb wptr: %d\n", get_wptr(ring)); + for (i = 0; i < gpu->nr_rings; i++) { + drm_printf(p, " - id: %d\n", i); + drm_printf(p, " iova: 0x%016llx\n", state->ring[i].iova); + drm_printf(p, " last-fence: %d\n", state->ring[i].seqno); + drm_printf(p, " retired-fence: %d\n", state->ring[i].fence); + drm_printf(p, " rptr: %d\n", state->ring[i].rptr); + drm_printf(p, " wptr: %d\n", state->ring[i].wptr); + drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); + + adreno_show_object(p, state->ring[i].data, + state->ring[i].data_size); } - /* dump these out in a form that can be parsed by demsm: */ - seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); - for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { - uint32_t start = adreno_gpu->registers[i]; - uint32_t end = adreno_gpu->registers[i+1]; - uint32_t addr; + if (state->bos) { + drm_puts(p, "bos:\n"); - for (addr = start; addr <= end; addr++) { - uint32_t val = gpu_read(gpu, addr); - seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); + for (i = 0; i < state->nr_bos; i++) { + drm_printf(p, " - iova: 0x%016llx\n", + state->bos[i].iova); + drm_printf(p, " size: %zd\n", state->bos[i].size); + + adreno_show_object(p, state->bos[i].data, + state->bos[i].size); } } + + drm_puts(p, "registers:\n"); + + for (i = 0; i < state->nr_registers; i++) { + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", + state->registers[i * 2] << 2, + state->registers[(i * 2) + 1]); + } } #endif @@ -565,7 +711,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, adreno_get_pwrlevels(&pdev->dev, gpu); - pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD); + pm_runtime_set_autosuspend_delay(&pdev->dev, + adreno_gpu->info->inactive_period); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index d6b0e7b813f4..4406776597fd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -84,6 +84,7 @@ struct adreno_info { enum adreno_quirks quirks; struct msm_gpu *(*init)(struct drm_device *dev); const char *zapfw; + u32 inactive_period; }; const struct adreno_info *adreno_info(struct adreno_rev rev); @@ -214,8 +215,9 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx); void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); -#ifdef CONFIG_DEBUG_FS -void adreno_show(struct msm_gpu *gpu, struct seq_file *m); +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) +void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct drm_printer *p); #endif void adreno_dump_info(struct msm_gpu *gpu); void adreno_dump(struct msm_gpu *gpu); @@ -228,6 +230,11 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *gpu); +void adreno_gpu_state_destroy(struct msm_gpu_state *state); + +int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); +int adreno_gpu_state_put(struct msm_gpu_state *state); + /* ringbuffer helpers (the parts that are adreno specific) */ static inline void |