summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSidath Senanayake <sidaths@google.com>2021-08-19 21:56:16 +0100
committerSidath Senanayake <sidaths@google.com>2021-08-19 23:35:54 +0100
commit24cf981f70b9258d0a63e3df75008dcd0e88e60b (patch)
tree1d262e31167882774c3fe9c84a0730e332830d07
parent5f5610c2d0250e36bf8ce6e15e9281a843053524 (diff)
downloadgpu-24cf981f70b9258d0a63e3df75008dcd0e88e60b.tar.gz
mali_kbase: platform: power: Explicitly track GPU power state
Store the view of GPU power state within the GPU platform integration itself rather than relying on querying PMU registers. Test: run cts-dev --include-filter "CtsDeqpTestCases dEQP-VK.protected_memory.*" Test: Repro steps for race condition from b/196269975#comment71 Test: Ensure inter-frame power off working Bug: 196269975 Bug: 196300136 Signed-off-by: Sidath Senanayake <sidaths@google.com> Change-Id: I86f9472b0a43139f28d78cd858608f054910b7ed
-rw-r--r--mali_kbase/platform/pixel/mali_kbase_config_platform.h25
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_power.c46
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_trace.h23
3 files changed, 51 insertions, 43 deletions
diff --git a/mali_kbase/platform/pixel/mali_kbase_config_platform.h b/mali_kbase/platform/pixel/mali_kbase_config_platform.h
index 8c7611a..f75fc39 100644
--- a/mali_kbase/platform/pixel/mali_kbase_config_platform.h
+++ b/mali_kbase/platform/pixel/mali_kbase_config_platform.h
@@ -106,6 +106,25 @@ extern struct protected_mode_ops pixel_protected_ops;
#define OF_DATA_NUM_MAX 128
#define CPU_FREQ_MAX INT_MAX
+enum gpu_power_state {
+ /* Mali GPUs have a hierarchy of power domains, which must be powered up
+ * in order and powered down in reverse order. Individual architectures
+ * and implementations may not allow each domain to be powered up or
+ * down independently of the others.
+ *
+ * The power state can thus be defined as the highest-level domain that
+ * is currently powered on.
+ *
+ * GLOBAL: The frontend (JM, CSF), including registers.
+ * COREGROUP: The L2 and AXI interface, Tiler, and MMU.
+ * STACKS: The shader cores.
+ */
+ GPU_POWER_LEVEL_OFF = 0,
+ GPU_POWER_LEVEL_GLOBAL = 1,
+ GPU_POWER_LEVEL_COREGROUP = 2,
+ GPU_POWER_LEVEL_STACKS = 3,
+};
+
/**
* enum gpu_pm_domain - Power domains on the GPU.
*
@@ -202,10 +221,10 @@ struct gpu_dvfs_metrics_uid_stats;
*
* @kbdev: The &struct kbase_device for the GPU.
*
- * @pm.lock: &struct mutex used to control access to the power down sequence.
+ * @pm.lock: &struct mutex used to control accesses to &state.
+ * @pm.state: Holds the current power state of the GPU.
* @pm.domain_devs Virtual pm domain devices.
* @pm.domain_links Links from pm domain devices to the real device.
- * @pm.state_lost: Stores whether the TOP domain has been powered off and state lost.
* @pm.domain: The power domain the GPU is in.
* @pm.status_reg_offset: Register offset to the G3D status in the PMU. Set via DT.
* @pm.status_local_power_mask: Mask to extract power status of the GPU. Set via DT.
@@ -277,11 +296,11 @@ struct pixel_context {
struct {
struct mutex lock;
+ enum gpu_power_state state;
struct device *domain_devs[GPU_PM_DOMAIN_COUNT];
struct device_link *domain_links[GPU_PM_DOMAIN_COUNT];
- bool state_lost;
struct exynos_pm_domain *domain;
unsigned int status_reg_offset;
unsigned int status_local_power_mask;
diff --git a/mali_kbase/platform/pixel/pixel_gpu_power.c b/mali_kbase/platform/pixel/pixel_gpu_power.c
index e117054..53a9ff0 100644
--- a/mali_kbase/platform/pixel/pixel_gpu_power.c
+++ b/mali_kbase/platform/pixel/pixel_gpu_power.c
@@ -44,16 +44,18 @@ static const char * const GPU_PM_DOMAIN_NAMES[GPU_PM_DOMAIN_COUNT] = {
*
* @kbdev: The &struct kbase_device for the GPU.
*
- * Powers off the CORES domain and issues trace points and events. Also powers on TOP and cancels
+ * Powers on the CORES domain and issues trace points and events. Also powers on TOP and cancels
* any pending suspend operations on it.
*
- * Context: Process context.
+ * Context: Process context. Requires the caller to hold the PM lock.
*/
static void gpu_pm_power_on_cores(struct kbase_device *kbdev)
{
struct pixel_context *pc = kbdev->platform_context;
u64 start_ns = ktime_get_ns();
+ lockdep_assert_held(&pc->pm.lock);
+
pm_runtime_get_sync(pc->pm.domain_devs[GPU_PM_DOMAIN_TOP]);
pm_runtime_get_sync(pc->pm.domain_devs[GPU_PM_DOMAIN_CORES]);
@@ -62,10 +64,13 @@ static void gpu_pm_power_on_cores(struct kbase_device *kbdev)
#ifdef CONFIG_MALI_MIDGARD_DVFS
gpu_dvfs_event_power_on(kbdev);
#endif
+
#if IS_ENABLED(CONFIG_GOOGLE_BCL)
if (pc->pm.bcl_dev)
google_init_gpu_ratio(pc->pm.bcl_dev);
#endif
+
+ pc->pm.state = GPU_POWER_LEVEL_STACKS;
}
/**
@@ -74,11 +79,8 @@ static void gpu_pm_power_on_cores(struct kbase_device *kbdev)
* @kbdev: The &struct kbase_device for the GPU.
*
* Powers off the CORES domain and issues trace points and events. Also marks the TOP domain for
- * delayed suspend.
- *
- * While the GPU power on sequence occurs only due to incoming GPU work, the power down sequence is
- * more complex in that it can be triggered by more than one event. In order to avoid races between
- * these power down triggers, we use the PM lock to ensure correct behaviour.
+ * delayed suspend. If the we have already performed these operations without an intervening call to
+ * &gpu_pm_power_on_cores, then we take no action.
*
* Context: Process context. Takes and releases the PM lock.
*/
@@ -89,8 +91,7 @@ static void gpu_pm_power_off_cores(struct kbase_device *kbdev)
mutex_lock(&pc->pm.lock);
- if (gpu_pm_get_power_state(kbdev)) {
-
+ if (pc->pm.state > GPU_POWER_LEVEL_GLOBAL) {
pm_runtime_put_sync(pc->pm.domain_devs[GPU_PM_DOMAIN_CORES]);
pm_runtime_mark_last_busy(pc->pm.domain_devs[GPU_PM_DOMAIN_TOP]);
@@ -101,6 +102,9 @@ static void gpu_pm_power_off_cores(struct kbase_device *kbdev)
#ifdef CONFIG_MALI_MIDGARD_DVFS
gpu_dvfs_event_power_off(kbdev);
#endif
+
+ /* We won't reach GPU_POWER_LEVEL_OFF until the autosuspend completes */
+ pc->pm.state = GPU_POWER_LEVEL_GLOBAL;
}
mutex_unlock(&pc->pm.lock);
@@ -125,15 +129,19 @@ static void gpu_pm_power_off_cores(struct kbase_device *kbdev)
static int gpu_pm_callback_power_on(struct kbase_device *kbdev)
{
struct pixel_context *pc = kbdev->platform_context;
- int ret = (pc->pm.state_lost ? 1 : 0);
+ int ret;
dev_dbg(kbdev->dev, "%s\n", __func__);
- if (pc->pm.state_lost)
- pc->pm.state_lost = false;
+ mutex_lock(&pc->pm.lock);
+
+ /* If the GPU is currently off, then state was lost */
+ ret = (pc->pm.state == GPU_POWER_LEVEL_OFF);
gpu_pm_power_on_cores(kbdev);
+ mutex_unlock(&pc->pm.lock);
+
return ret;
}
@@ -184,16 +192,9 @@ static void gpu_pm_callback_power_off(struct kbase_device *kbdev)
*/
static void gpu_pm_callback_power_suspend(struct kbase_device *kbdev)
{
- struct pixel_context *pc = kbdev->platform_context;
-
dev_dbg(kbdev->dev, "%s\n", __func__);
- if (pc->pm.state_lost)
- return;
-
gpu_pm_power_off_cores(kbdev);
-
- pc->pm.state_lost = true;
}
#ifdef KBASE_PM_RUNTIME
@@ -216,9 +217,12 @@ static int gpu_pm_callback_power_runtime_suspend(struct device *dev)
dev_dbg(kbdev->dev, "%s\n", __func__);
- WARN_ON(pc->pm.state_lost);
+ mutex_lock(&pc->pm.lock);
+
+ WARN_ON(pc->pm.state > GPU_POWER_LEVEL_GLOBAL);
+ pc->pm.state = GPU_POWER_LEVEL_OFF;
- pc->pm.state_lost = true;
+ mutex_unlock(&pc->pm.lock);
#ifdef CONFIG_MALI_MIDGARD_DVFS
kbase_pm_metrics_stop(kbdev);
diff --git a/mali_kbase/platform/pixel/pixel_gpu_trace.h b/mali_kbase/platform/pixel/pixel_gpu_trace.h
index ef7cc88..775adde 100644
--- a/mali_kbase/platform/pixel/pixel_gpu_trace.h
+++ b/mali_kbase/platform/pixel/pixel_gpu_trace.h
@@ -6,25 +6,6 @@
#ifndef _PIXEL_GPU_TRACE_H_
#define _PIXEL_GPU_TRACE_H_
-enum gpu_power_state {
- /* Mali GPUs have a hierarchy of power domains, which must be powered up
- * in order and powered down in reverse order. Individual architectures
- * and implementations may not allow each domain to be powered up or
- * down independently of the others.
- *
- * The power state can thus be defined as the highest-level domain that
- * is currently powered on.
- *
- * GLOBAL: The frontend (JM, CSF), including registers.
- * COREGROUP: The L2 and AXI interface, Tiler, and MMU.
- * STACKS: The shader cores.
- */
- GPU_POWER_LEVEL_OFF = 0,
- GPU_POWER_LEVEL_GLOBAL = 1,
- GPU_POWER_LEVEL_COREGROUP = 2,
- GPU_POWER_LEVEL_STACKS = 3,
-};
-
#endif /* _PIXEL_GPU_TRACE_H_ */
#undef TRACE_SYSTEM
@@ -33,8 +14,12 @@ enum gpu_power_state {
#if !defined(_TRACE_PIXEL_GPU_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_PIXEL_GPU_H
+/* Linux includes */
#include <linux/tracepoint.h>
+/* Pixel integration includes */
+#include "mali_kbase_config_platform.h"
+
#define GPU_POWER_STATE_SYMBOLIC_STRINGS \
{GPU_POWER_LEVEL_STACKS, "STACKS"}, \
{GPU_POWER_LEVEL_COREGROUP, "COREGROUP"}, \