From patchwork Tue Apr 17 22:44:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jordan Crouse X-Patchwork-Id: 10346999 X-Patchwork-Delegate: agross@codeaurora.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4ABCC6039A for ; Tue, 17 Apr 2018 22:44:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1F5C427F10 for ; Tue, 17 Apr 2018 22:44:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 13C8A27F3E; Tue, 17 Apr 2018 22:44:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E980D27F10 for ; Tue, 17 Apr 2018 22:44:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752633AbeDQWoz (ORCPT ); Tue, 17 Apr 2018 18:44:55 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:46564 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752209AbeDQWox (ORCPT ); Tue, 17 Apr 2018 18:44:53 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 6E8AD60FB1; Tue, 17 Apr 2018 22:44:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1524005093; bh=GjDAu68NKWs95cR8RbOfPnEK4nqtpXe9ImZxbLFoKVo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mFDdSSozquxw/Y9gAaNHzSN6eXzygOMa2vqm3DAhRCHgiUzRUHuwSsEF2zTAo0j2w lUUexSKszVKjZkdophCt1Wg+HLt3UaLiBA0agYb39BFHkdNKQg8YfoiJA0yx2PJR84 Ky8K9PHIsOPPSq7V1CIxEtiqdMs4CT9q+eIgIt3k= Received: from jcrouse-lnx.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: jcrouse@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 3999160FB1; Tue, 17 Apr 2018 22:44:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1524005091; bh=GjDAu68NKWs95cR8RbOfPnEK4nqtpXe9ImZxbLFoKVo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dvINRUDp150pqOBTOHvyQ+qJ/KNLrxlmj7snIQoLdo3bmjdOCy7R+iqrsScXg1hbm QNN44RFFlqookYszBn4pauC0NOJfGBW00fPtp23aUdiOWhSMAxPsdaM3G/xBPwEgxg hYxJblNJS08Fd4gK179/vzUToosBMgmucG3ocJIg= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 3999160FB1 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=jcrouse@codeaurora.org From: Jordan Crouse To: freedreno@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org Subject: [PATCH 09/10] drm/msm/adreno: Add a5xx specific registers for the GPU state Date: Tue, 17 Apr 2018 16:44:40 -0600 Message-Id: <20180417224441.32355-10-jcrouse@codeaurora.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180417224441.32355-1-jcrouse@codeaurora.org> References: <20180417224441.32355-1-jcrouse@codeaurora.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP HLSQ, SP and TP registers are only accessible from a special aperture and to make matters worse the aperture is blocked from the CPU on targets that can support secure rendering. Luckily the GPU hardware has its own purpose built register dumper that can access the registers from the aperture. Add a5xx specific code to program the crashdumper and retrieve the wayward registers and dump them for the crash state. Also, remove a block of registers the regular CPU accessible list that aren't useful for debug which helps reduce the size of the crash state file by a goodly amount. Signed-off-by: Jordan Crouse --- Documentation/gpu/drm-msm-crash-dump.txt | 4 + drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 8 +- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 8 +- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 236 +++++++++++++++++++++-- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 23 +-- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 4 +- 6 files changed, 252 insertions(+), 31 deletions(-) diff --git a/Documentation/gpu/drm-msm-crash-dump.txt b/Documentation/gpu/drm-msm-crash-dump.txt index df25afd10602..f84a47a9ca92 100644 --- a/Documentation/gpu/drm-msm-crash-dump.txt +++ b/Documentation/gpu/drm-msm-crash-dump.txt @@ -33,3 +33,7 @@ registers: # Sets of register values. This section can be used multiple # on its own line. - [offset, value] # offset: [hex] byte offset of the register # value: [hex] value of the register + +registers-hlsq: # (5xx only) Same format as registers. Register data that + # only accessible from the HLSQ aperture captured by the + # HW based crashdumper diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index fc502e412132..669c2d4b070d 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -421,10 +421,12 @@ static void a3xx_dump(struct msm_gpu *gpu) static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu) { - struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - if (IS_ERR(state)) - return state; + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 8129cf037db1..7c4e6dc1ed59 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -457,10 +457,12 @@ static const unsigned int a4xx_registers[] = { static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) { - struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - if (IS_ERR(state)) - return state; + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 836a1df1f257..8220077bd768 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -19,6 +19,7 @@ #include #include #include +#include #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,25 +1197,233 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) return 0; } +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) +{ + dumper->ptr = msm_gem_kernel_new_locked(gpu->dev, + SZ_1M, MSM_BO_UNCACHED, gpu->aspace, + &dumper->bo, &dumper->iova); + + 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 msm_gpu_state *state; + struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), + GFP_KERNEL); - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ + if (!a5xx_state) + return ERR_PTR(-ENOMEM); + + /* Temporarily disable hardware clock gating before reading the hw */ a5xx_set_hwcg(gpu, false); - state = adreno_gpu_state_get(gpu); + /* 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); - if (!IS_ERR(state)) - state->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 state; + 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 static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) { @@ -1244,14 +1454,14 @@ static const struct adreno_gpu_funcs funcs = { .irq = a5xx_irq, .destroy = a5xx_destroy, #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) - .show = adreno_show, + .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 = adreno_gpu_state_put, + .gpu_state_put = a5xx_gpu_state_put, }, .get_timestamp = a5xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 1f520875a7fb..d6e42554b1cb 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -369,16 +369,11 @@ bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) return false; } -struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) +int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct msm_gpu_state *state; int i, count = 0; - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return ERR_PTR(-ENOMEM); - kref_init(&state->ref); do_gettimeofday(&state->time); @@ -433,14 +428,12 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) state->nr_registers = count; } - return state; + return 0; } -static void adreno_gpu_state_destroy(struct kref *kref) +void adreno_gpu_state_destroy(struct msm_gpu_state *state) { int i; - struct msm_gpu_state *state = container_of(kref, - struct msm_gpu_state, ref); for (i = 0; i < ARRAY_SIZE(state->ring); i++) kfree(state->ring[i].data); @@ -448,6 +441,14 @@ static void adreno_gpu_state_destroy(struct kref *kref) 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); } @@ -456,7 +457,7 @@ 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_destroy); + return kref_put(&state->ref, adreno_gpu_state_kref_destroy); } #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 077bf1149c0b..942d69563090 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -228,7 +228,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, int nr_rings); void adreno_gpu_cleanup(struct adreno_gpu *gpu); -struct msm_gpu_state *adreno_gpu_state_get(struct msm_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) */