Expose the GL2 high-temporal residency threshold
(GL2C_RESIDENCY_CTRL.REG_THRESHOLD) through a new per-device debugfs
file, /sys/kernel/debug/dri/*/amdgpu_gl2_ht_threshold.

A read returns the current threshold as a decimal number; a write parses
a decimal value and range-checks it against the field width. The get/set
logic is implemented as gfx_funcs callbacks in gfx_v12_1, so the file is
only created on ASICs that support the feature (GC IP >= 12.1.0).

Signed-off-by: Alex Sierra <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c     | 92 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h     | 12 +++
 drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c      | 51 ++++++++++++
 4 files changed, 156 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index eb04583357df..6c2e39de7bb2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -2216,6 +2216,7 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
        amdgpu_debugfs_jpeg_sched_mask_init(adev);
        amdgpu_debugfs_gfx_sched_mask_init(adev);
        amdgpu_debugfs_compute_sched_mask_init(adev);
+       amdgpu_debugfs_gl2_ht_threshold_init(adev);
        amdgpu_debugfs_sdma_sched_mask_init(adev);
 
        amdgpu_ras_debugfs_create_all(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 1bbb3d646cfe..1047339295e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -3327,6 +3327,98 @@ void amdgpu_debugfs_compute_sched_mask_init(struct 
amdgpu_device *adev)
 #endif
 }
 
+/*
+ * debugfs to read/write the GL2 high-temporal residency threshold
+ * (GL2C_RESIDENCY_CTRL.REG_THRESHOLD). The value is expressed as a decimal
+ * number; writes are range-checked by the ASIC set() callback.
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int amdgpu_debugfs_gl2_ht_threshold_get(void *data, u64 *val)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)data;
+       u32 threshold = 0;
+       int r;
+
+       if (!adev)
+               return -ENODEV;
+       if (!adev->gfx.funcs || !adev->gfx.funcs->get_gl2_ht_threshold)
+               return -EOPNOTSUPP;
+       /* Only SPX/DPX partition modes support GL2 residency control. */
+       if (!amdgpu_gfx_gl2_residency_mode_supported(adev))
+               return -EOPNOTSUPP;
+
+       r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
+       if (r < 0) {
+               pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+               return r;
+       }
+
+       r = adev->gfx.funcs->get_gl2_ht_threshold(adev, &threshold);
+
+       pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
+       pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+
+       if (r)
+               return r;
+
+       *val = threshold;
+       return 0;
+}
+
+static int amdgpu_debugfs_gl2_ht_threshold_set(void *data, u64 val)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)data;
+       int r;
+
+       if (!adev)
+               return -ENODEV;
+       if (!adev->gfx.funcs || !adev->gfx.funcs->set_gl2_ht_threshold)
+               return -EOPNOTSUPP;
+       /* Only SPX/DPX partition modes support GL2 residency control. */
+       if (!amdgpu_gfx_gl2_residency_mode_supported(adev))
+               return -EOPNOTSUPP;
+       if (val > U32_MAX)
+               return -EINVAL;
+
+       r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
+       if (r < 0) {
+               pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+               return r;
+       }
+
+       r = adev->gfx.funcs->set_gl2_ht_threshold(adev, (u32)val);
+
+       pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
+       pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+
+       return r;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gl2_ht_threshold_fops,
+                        amdgpu_debugfs_gl2_ht_threshold_get,
+                        amdgpu_debugfs_gl2_ht_threshold_set, "%llu\n");
+
+#endif
+
+void amdgpu_debugfs_gl2_ht_threshold_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       struct drm_minor *minor = adev_to_drm(adev)->primary;
+       struct dentry *root = minor->debugfs_root;
+
+       /*
+        * Only expose the file on ASICs that implement the GL2 HT threshold
+        * control. This is currently gfx12.1+ (GC IP >= 12.1.0).
+        */
+       if (!adev->gfx.funcs || !adev->gfx.funcs->get_gl2_ht_threshold ||
+           !adev->gfx.funcs->set_gl2_ht_threshold)
+               return;
+
+       debugfs_create_file("amdgpu_gl2_ht_threshold", 0600, root, adev,
+                           &amdgpu_debugfs_gl2_ht_threshold_fops);
+#endif
+}
+
 int amdgpu_gfx_ring_preempt_ib(struct amdgpu_ring *ring)
 {
        struct amdgpu_device *adev = ring->adev;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index 1b01dacddd25..34db5e7e4165 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -398,6 +398,12 @@ struct amdgpu_gfx_funcs {
         * persisting GL2 cache is accounted and programmed. SOC-specific.
         */
        u32 (*get_num_gl2_instances)(struct amdgpu_device *adev);
+       /* Get/set the GL2 high-temporal residency threshold
+        * (GL2C_RESIDENCY_CTRL.REG_THRESHOLD). Only implemented on ASICs that
+        * support the feature; used to expose it through debugfs.
+        */
+       int (*get_gl2_ht_threshold)(struct amdgpu_device *adev, u32 *val);
+       int (*set_gl2_ht_threshold)(struct amdgpu_device *adev, u32 val);
 };
 
 struct sq_work {
@@ -607,6 +613,11 @@ struct amdgpu_gfx {
 
        /* Persisting GL2 cache request accounting (gfx12.1+) */
        struct amdgpu_gl2_persisting_mgr        gl2_persisting;
+
+       /* Placeholder software shadow of GL2C_RESIDENCY_CTRL.REG_THRESHOLD
+        * until the real register access is wired up (gfx12.1+).
+        */
+       u32                             gl2_ht_threshold;
 };
 
 struct amdgpu_gfx_deferred_entry {
@@ -755,6 +766,7 @@ void amdgpu_gfx_csb_preamble_end(u32 *buffer, u32 count);
 
 void amdgpu_debugfs_gfx_sched_mask_init(struct amdgpu_device *adev);
 void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev);
+void amdgpu_debugfs_gl2_ht_threshold_init(struct amdgpu_device *adev);
 
 int amdgpu_gfx_ring_preempt_ib(struct amdgpu_ring *ring);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
index c3a165ca5998..7efd4f2e26eb 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c
@@ -56,6 +56,13 @@
 #define GL2C_RESIDENCY_CTRL__RESIDENCY_WAYS__SHIFT     0x0
 #define GL2C_RESIDENCY_CTRL__RESIDENCY_WAYS_MASK       0x0000000FL
 
+#define GL2C_RESIDENCY_CTRL__REG_THRESHOLD__SHIFT      0x4
+#define GL2C_RESIDENCY_CTRL__REG_THRESHOLD_MASK        0x000003F0L
+
+#define GL2C_RESIDENCY_THRESHOLD_MAX \
+       (GL2C_RESIDENCY_CTRL__REG_THRESHOLD_MASK >> \
+        GL2C_RESIDENCY_CTRL__REG_THRESHOLD__SHIFT)
+
 #define RLCG_UCODE_LOADING_START_ADDRESS       0x00002000L
 
 #define regCP_HQD_EOP_CONTROL_DEFAULT                                          
   0x00000000
@@ -782,6 +789,48 @@ static u32 gfx_v12_1_get_num_gl2_instances(struct 
amdgpu_device *adev)
        return hweight32(adev->aid_mask);
 }
 
+/*
+ * Read back the current GL2 high-temporal residency threshold
+ * (GL2C_RESIDENCY_CTRL.REG_THRESHOLD).
+ */
+static int gfx_v12_1_get_gl2_ht_threshold(struct amdgpu_device *adev, u32 *val)
+{
+       *val = adev->gfx.gl2_ht_threshold;
+
+       dev_info(adev->dev,
+                "GL2 HT threshold read (placeholder): REG_THRESHOLD=%u\n",
+                *val);
+
+       return 0;
+}
+
+/*
+ * Program the GL2 high-temporal residency threshold
+ * (GL2C_RESIDENCY_CTRL.REG_THRESHOLD).
+ *
+ */
+static int gfx_v12_1_set_gl2_ht_threshold(struct amdgpu_device *adev, u32 val)
+{
+       /*
+        * REG_THRESHOLD is a PF-only register. As with RESIDENCY_WAYS it must
+        * never be programmed by a guest in multi-VF mode, where it would
+        * disturb the shared GL2 policy of the other VFs.
+        */
+       if (amdgpu_sriov_multi_vf_mode(adev))
+               return -EPERM;
+
+       if (val > GL2C_RESIDENCY_THRESHOLD_MAX)
+               return -EINVAL;
+
+       adev->gfx.gl2_ht_threshold = val;
+
+       dev_info(adev->dev,
+                "GL2 HT threshold write (placeholder): REG_THRESHOLD=%u\n",
+                val);
+
+       return 0;
+}
+
 static const struct amdgpu_gfx_funcs gfx_v12_1_gfx_funcs = {
        .get_gpu_clock_counter = &gfx_v12_1_get_gpu_clock_counter,
        .select_se_sh = &gfx_v12_1_xcc_select_se_sh,
@@ -795,6 +844,8 @@ static const struct amdgpu_gfx_funcs gfx_v12_1_gfx_funcs = {
        .set_persisting_gl2_cache = &gfx_v12_1_set_persisting_gl2_cache,
        .xcc_to_gl2_instance_mask = &gfx_v12_1_xcc_to_gl2_instance_mask,
        .get_num_gl2_instances = &gfx_v12_1_get_num_gl2_instances,
+       .get_gl2_ht_threshold = &gfx_v12_1_get_gl2_ht_threshold,
+       .set_gl2_ht_threshold = &gfx_v12_1_set_gl2_ht_threshold,
 };
 
 static int gfx_v12_1_gpu_early_init(struct amdgpu_device *adev)
-- 
2.34.1

Reply via email to