From patchwork Thu Mar 8 06:06:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sharat Masetty X-Patchwork-Id: 10266585 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 175F06037E for ; Thu, 8 Mar 2018 06:07:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05F8E2974B for ; Thu, 8 Mar 2018 06:07:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EE8582974C; Thu, 8 Mar 2018 06:07:19 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 219C329750 for ; Thu, 8 Mar 2018 06:07:19 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3CFB56E813; Thu, 8 Mar 2018 06:07:14 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp.codeaurora.org (smtp.codeaurora.org [198.145.29.96]) by gabe.freedesktop.org (Postfix) with ESMTPS id C61F46E809; Thu, 8 Mar 2018 06:07:11 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 6A1A660390; Thu, 8 Mar 2018 06:07:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1520489231; bh=LJRo4I+dzR4yikfXK98rhvfuozrVauP+BVz8fJOfvlI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mNnWv41LwIALloEXjjC/Jl9DVWzGXz9p+hDrkpLR7Z85cZT7K9j7d8+3PCOQL74Ia 4czzIvVb5mH2fNU6HEjia+O69vVbb8O9iocmky8YE3AW+uIdEIoY/LaJsFhxDa50af CBKQxaXdjmv90L8cWRHJP8tXA4DgBVneryfG8CXU= Received: from smasetty-linux.qualcomm.com (blr-c-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.19.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: smasetty@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 25AC060A05; Thu, 8 Mar 2018 06:07:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1520489228; bh=LJRo4I+dzR4yikfXK98rhvfuozrVauP+BVz8fJOfvlI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kZOyn5zDFgTENmNV/QWHkNGUtzuVc87fOjxsdcy/UOjs2pwDFo8Wv30SMrf6hZX8u 7JjNhVn2FQDhbhnw5i0ImYrGUN9FIIjrC6hcwsZe7tb2k0bzkY6ahKNzBxWk1pY/dy NfvLmhcQLdcSSjgQwHvVtAK1v77pSR+41e8yBAwA= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 25AC060A05 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=smasetty@codeaurora.org From: Sharat Masetty To: freedreno@lists.freedesktop.org Subject: [PATCH 5/6] drm/msm/Adreno: Refactor some preemption code Date: Thu, 8 Mar 2018 11:36:24 +0530 Message-Id: <1520489185-21828-6-git-send-email-smasetty@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1520489185-21828-1-git-send-email-smasetty@codeaurora.org> References: <1520489185-21828-1-git-send-email-smasetty@codeaurora.org> X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-arm-msm@vger.kernel.org, Sharat Masetty , dri-devel@lists.freedesktop.org MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP The preemption state machine related code is same across Adreno targets, so move the common code to a common header file to avoid code duplication. Signed-off-by: Sharat Masetty --- drivers/gpu/drm/msm/adreno/a5xx_gpu.h | 26 --------------- drivers/gpu/drm/msm/adreno/a5xx_preempt.c | 55 +++++++++---------------------- drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 26 --------------- drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 55 +++++++++---------------------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 54 ++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 132 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index 7d71860..45535f7 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -54,32 +54,6 @@ struct a5xx_gpu { #endif /* - * In order to do lockless preemption we use a simple state machine to progress - * through the process. - * - * PREEMPT_NONE - no preemption in progress. Next state START. - * PREEMPT_START - The trigger is evaulating if preemption is possible. Next - * states: TRIGGERED, NONE - * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next - * state: NONE. - * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next - * states: FAULTED, PENDING - * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger - * recovery. Next state: N/A - * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is - * checking the success of the operation. Next state: FAULTED, NONE. - */ - -enum preempt_state { - PREEMPT_NONE = 0, - PREEMPT_START, - PREEMPT_ABORT, - PREEMPT_TRIGGERED, - PREEMPT_FAULTED, - PREEMPT_PENDING, -}; - -/* * struct a5xx_preempt_record is a shared buffer between the microcode and the * CPU to store the state for preemption. The record itself is much larger * (64k) but most of that is used by the CP for storage. diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c index 40f4840..faf844b 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -14,37 +14,6 @@ #include "msm_gem.h" #include "a5xx_gpu.h" -/* - * Try to transition the preemption state from old to new. Return - * true on success or false if the original state wasn't 'old' - */ -static inline bool try_preempt_state(struct a5xx_gpu *a5xx_gpu, - enum preempt_state old, enum preempt_state new) -{ - enum preempt_state cur = atomic_cmpxchg(&a5xx_gpu->preempt_state, - old, new); - - return (cur == old); -} - -/* - * Force the preemption state to the specified state. This is used in cases - * where the current state is known and won't change - */ -static inline void set_preempt_state(struct a5xx_gpu *gpu, - enum preempt_state new) -{ - /* - * preempt_state may be read by other cores trying to trigger a - * preemption or in the interrupt handler so barriers are needed - * before... - */ - smp_mb__before_atomic(); - atomic_set(&gpu->preempt_state, new); - /* ... and after*/ - smp_mb__after_atomic(); -} - /* Write the most recent wptr for the given ring into the hardware */ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { @@ -89,7 +58,8 @@ static void a5xx_preempt_timer(unsigned long data) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_FAULTED)) return; dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); @@ -111,7 +81,8 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) * Try to start preemption by moving from NONE to START. If * unsuccessful, a preemption is already in flight */ - if (!try_preempt_state(a5xx_gpu, PREEMPT_NONE, PREEMPT_START)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_NONE, PREEMPT_START)) return; /* Get the next ring to preempt to */ @@ -134,9 +105,11 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) * and can safely update the write pointer. */ - set_preempt_state(a5xx_gpu, PREEMPT_ABORT); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_ABORT); update_wptr(gpu, a5xx_gpu->cur_ring); - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_NONE); return; } @@ -156,7 +129,7 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) mod_timer(&a5xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); /* Set the preemption state to triggered */ - set_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_TRIGGERED); /* Make sure everything is written before hitting the button */ wmb(); @@ -173,7 +146,8 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_PENDING)) return; /* Delete the preemption watchdog timer */ @@ -187,7 +161,8 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) */ status = gpu_read(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL); if (unlikely(status)) { - set_preempt_state(a5xx_gpu, PREEMPT_FAULTED); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_FAULTED); dev_err(dev->dev, "%s: Preemption failed to complete\n", gpu->name); queue_work(priv->wq, &gpu->recover_work); @@ -199,7 +174,7 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) update_wptr(gpu, a5xx_gpu->cur_ring); - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_NONE); } void a5xx_preempt_hw_init(struct msm_gpu *gpu) @@ -219,7 +194,7 @@ void a5xx_preempt_hw_init(struct msm_gpu *gpu) REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI, 0); /* Reset the preemption state */ - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_NONE); /* Always come up on rb 0 */ a5xx_gpu->cur_ring = gpu->rb[0]; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index aca1d7d..21ab701 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -54,32 +54,6 @@ struct a6xx_gpu { (a6xx_gpu->scratch_iova + (ring_id * sizeof(uint64_t))) /* - * In order to do lockless preemption we use a simple state machine to progress - * through the process. - * - * PREEMPT_NONE - no preemption in progress. Next state START. - * PREEMPT_START - The trigger is evaluating if preemption is possible. Next - * states: TRIGGERED, NONE - * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next - * state: NONE. - * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next - * states: FAULTED, PENDING - * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger - * recovery. Next state: N/A - * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is - * checking the success of the operation. Next state: FAULTED, NONE. - */ - -enum a6xx_preempt_state { - PREEMPT_NONE = 0, - PREEMPT_START, - PREEMPT_ABORT, - PREEMPT_TRIGGERED, - PREEMPT_FAULTED, - PREEMPT_PENDING, -}; - -/* * ID values used by SET_PSEUDO_REG PM4 command. These determine which of the * various internal CP registers to write to. Used in the save/restore * preemption sequence. diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index 60df6c5..0d2b612 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -5,37 +5,6 @@ #include "a6xx_gpu.h" #include "a6xx_gmu.xml.h" -/* - * Try to transition the preemption state from old to new. Return - * true on success or false if the original state wasn't 'old' - */ -static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, - enum a6xx_preempt_state old, enum a6xx_preempt_state new) -{ - enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, - old, new); - - return (cur == old); -} - -/* - * Force the preemption state to the specified state. This is used in cases - * where the current state is known and won't change - */ -static inline void set_preempt_state(struct a6xx_gpu *gpu, - enum a6xx_preempt_state new) -{ - /* - * preempt_state may be read by other cores trying to trigger a - * preemption or in the interrupt handler so barriers are needed - * before... - */ - smp_mb__before_atomic(); - atomic_set(&gpu->preempt_state, new); - /* ... and after*/ - smp_mb__after_atomic(); -} - /* Write the most recent wptr for the given ring into the hardware */ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { @@ -80,7 +49,8 @@ static void a6xx_preempt_timer(unsigned long data) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_FAULTED)) return; dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); @@ -95,7 +65,8 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_PENDING)) return; /* Delete the preemption watchdog timer */ @@ -110,7 +81,8 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) */ status = gpu_read(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL); if (unlikely(status & 0x1)) { - set_preempt_state(a6xx_gpu, PREEMPT_FAULTED); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_FAULTED); dev_err(dev->dev, "%s: Preemption failed to complete\n", gpu->name); queue_work(priv->wq, &gpu->recover_work); @@ -122,7 +94,7 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) update_wptr(gpu, a6xx_gpu->cur_ring); - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_NONE); } void a6xx_preempt_hw_init(struct msm_gpu *gpu) @@ -151,7 +123,7 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x1); /* Reset the preemption state */ - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_NONE); /* Always come up on rb 0 */ a6xx_gpu->cur_ring = gpu->rb[0]; @@ -175,7 +147,8 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) * Try to start preemption by moving from NONE to START. If * unsuccessful, a preemption is already in flight */ - if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_NONE, PREEMPT_START)) return; cntl = (((a6xx_gpu->preempt_level << 6) & 0xC0) | @@ -190,9 +163,11 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) * one do nothing except to update the wptr to the latest and greatest */ if (!ring || (a6xx_gpu->cur_ring == ring)) { - set_preempt_state(a6xx_gpu, PREEMPT_ABORT); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_ABORT); update_wptr(gpu, a6xx_gpu->cur_ring); - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_NONE); return; } @@ -243,7 +218,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); /* Set the preemption state to triggered */ - set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_TRIGGERED); /* Make sure everything is written before hitting the button */ wmb(); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 94764d0..bb9affd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -368,4 +368,58 @@ static inline uint32_t get_wptr(struct msm_ringbuffer *ring) ((1 << 29) \ ((ilog2((_len)) & 0x1F) << 24) | (((_reg) << 2) & 0xFFFFF)) +/* + * In order to do lockless preemption we use a simple state machine to progress + * through the process. + * + * PREEMPT_NONE - no preemption in progress. Next state START. + * PREEMPT_START - The trigger is evaluating if preemption is possible. Next + * states: TRIGGERED, NONE + * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next + * state: NONE. + * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next + * states: FAULTED, PENDING + * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger + * recovery. Next state: N/A + * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is + * checking the success of the operation. Next state: FAULTED, NONE. + */ +enum adreno_preempt_state { + PREEMPT_NONE = 0, + PREEMPT_START, + PREEMPT_ABORT, + PREEMPT_TRIGGERED, + PREEMPT_FAULTED, + PREEMPT_PENDING, +}; + +/* + * Try to transition the preemption state from old to new. Return + * true on success or false if the original state wasn't 'old' + */ +static inline bool adreno_try_preempt_state(atomic_t *preempt_state, + enum adreno_preempt_state old, enum adreno_preempt_state new) +{ + enum adreno_preempt_state cur = atomic_cmpxchg(preempt_state, old, new); + + return (cur == old); +} + +/* + * Force the preemption state to the specified state. This is used in cases + * where the current state is known and won't change + */ +static inline void adreno_set_preempt_state(atomic_t *preempt_state, + enum adreno_preempt_state new) +{ + /* + * adreno_preempt_state may be read by other cores trying to trigger a + * preemption or in the interrupt handler so barriers are needed + * before... + */ + smp_mb__before_atomic(); + atomic_set(preempt_state, new); + /* ... and after*/ + smp_mb__after_atomic(); +} #endif /* __ADRENO_GPU_H__ */