]> git.dujemihanovic.xyz Git - linux.git/commitdiff
drm/xe: Runtime PM wake on every sysfs call
authorRodrigo Vivi <rodrigo.vivi@intel.com>
Thu, 22 Feb 2024 16:39:28 +0000 (11:39 -0500)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Mon, 26 Feb 2024 14:06:45 +0000 (09:06 -0500)
Let's ensure our PCI device is awaken on every sysfs call.
Let's increase the runtime_pm protection and start moving
that to the outer bounds.

For now, for the files with small number of attr functions,
let's only call the runtime pm functions directly.
For the hw_engines entries with many files, let's add
the sysfs_ops wrapper.

Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240222163937.138342-5-rodrigo.vivi@intel.com
drivers/gpu/drm/xe/xe_device_sysfs.c
drivers/gpu/drm/xe/xe_gt_freq.c
drivers/gpu/drm/xe/xe_gt_idle.c
drivers/gpu/drm/xe/xe_gt_throttle_sysfs.c
drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c
drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.h
drivers/gpu/drm/xe/xe_tile_sysfs.c

index 99113a5a2b84990a1faddf3e03affa414a1cf4de..e47c8ad1bb17a02da5e5f7c10d04ee4205da0434 100644 (file)
@@ -35,7 +35,9 @@ vram_d3cold_threshold_show(struct device *dev,
        if (!xe)
                return -EINVAL;
 
+       xe_pm_runtime_get(xe);
        ret = sysfs_emit(buf, "%d\n", xe->d3cold.vram_threshold);
+       xe_pm_runtime_put(xe);
 
        return ret;
 }
@@ -58,7 +60,9 @@ vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr,
 
        drm_dbg(&xe->drm, "vram_d3cold_threshold: %u\n", vram_d3cold_threshold);
 
+       xe_pm_runtime_get(xe);
        ret = xe_pm_set_vram_threshold(xe, vram_d3cold_threshold);
+       xe_pm_runtime_put(xe);
 
        return ret ?: count;
 }
index e5b0f4ecdbe8261ee5c3fa9530a30dc2fd46c14b..32b9a743629c1154b3f4963750441cdfde775145 100644 (file)
@@ -15,6 +15,7 @@
 #include "xe_gt_sysfs.h"
 #include "xe_gt_throttle_sysfs.h"
 #include "xe_guc_pc.h"
+#include "xe_pm.h"
 
 /**
  * DOC: Xe GT Frequency Management
@@ -49,12 +50,23 @@ dev_to_pc(struct device *dev)
        return &kobj_to_gt(dev->kobj.parent)->uc.guc.pc;
 }
 
+static struct xe_device *
+dev_to_xe(struct device *dev)
+{
+       return gt_to_xe(kobj_to_gt(dev->kobj.parent));
+}
+
 static ssize_t act_freq_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct xe_guc_pc *pc = dev_to_pc(dev);
+       u32 freq;
+
+       xe_pm_runtime_get(dev_to_xe(dev));
+       freq = xe_guc_pc_get_act_freq(pc);
+       xe_pm_runtime_put(dev_to_xe(dev));
 
-       return sysfs_emit(buf, "%d\n", xe_guc_pc_get_act_freq(pc));
+       return sysfs_emit(buf, "%d\n", freq);
 }
 static DEVICE_ATTR_RO(act_freq);
 
@@ -65,7 +77,9 @@ static ssize_t cur_freq_show(struct device *dev,
        u32 freq;
        ssize_t ret;
 
+       xe_pm_runtime_get(dev_to_xe(dev));
        ret = xe_guc_pc_get_cur_freq(pc, &freq);
+       xe_pm_runtime_put(dev_to_xe(dev));
        if (ret)
                return ret;
 
@@ -77,8 +91,13 @@ static ssize_t rp0_freq_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct xe_guc_pc *pc = dev_to_pc(dev);
+       u32 freq;
+
+       xe_pm_runtime_get(dev_to_xe(dev));
+       freq = xe_guc_pc_get_rp0_freq(pc);
+       xe_pm_runtime_put(dev_to_xe(dev));
 
-       return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rp0_freq(pc));
+       return sysfs_emit(buf, "%d\n", freq);
 }
 static DEVICE_ATTR_RO(rp0_freq);
 
@@ -86,8 +105,13 @@ static ssize_t rpe_freq_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct xe_guc_pc *pc = dev_to_pc(dev);
+       u32 freq;
+
+       xe_pm_runtime_get(dev_to_xe(dev));
+       freq = xe_guc_pc_get_rpe_freq(pc);
+       xe_pm_runtime_put(dev_to_xe(dev));
 
-       return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpe_freq(pc));
+       return sysfs_emit(buf, "%d\n", freq);
 }
 static DEVICE_ATTR_RO(rpe_freq);
 
@@ -107,7 +131,9 @@ static ssize_t min_freq_show(struct device *dev,
        u32 freq;
        ssize_t ret;
 
+       xe_pm_runtime_get(dev_to_xe(dev));
        ret = xe_guc_pc_get_min_freq(pc, &freq);
+       xe_pm_runtime_put(dev_to_xe(dev));
        if (ret)
                return ret;
 
@@ -125,7 +151,9 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
+       xe_pm_runtime_get(dev_to_xe(dev));
        ret = xe_guc_pc_set_min_freq(pc, freq);
+       xe_pm_runtime_put(dev_to_xe(dev));
        if (ret)
                return ret;
 
@@ -140,7 +168,9 @@ static ssize_t max_freq_show(struct device *dev,
        u32 freq;
        ssize_t ret;
 
+       xe_pm_runtime_get(dev_to_xe(dev));
        ret = xe_guc_pc_get_max_freq(pc, &freq);
+       xe_pm_runtime_put(dev_to_xe(dev));
        if (ret)
                return ret;
 
@@ -158,7 +188,9 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
+       xe_pm_runtime_get(dev_to_xe(dev));
        ret = xe_guc_pc_set_max_freq(pc, freq);
+       xe_pm_runtime_put(dev_to_xe(dev));
        if (ret)
                return ret;
 
index 9fcae65b64699eadb80a82b06386588a8af07f86..2984680de3f934bf27719b54cdb4e4b9f56755a6 100644 (file)
@@ -12,6 +12,7 @@
 #include "xe_guc_pc.h"
 #include "regs/xe_gt_regs.h"
 #include "xe_mmio.h"
+#include "xe_pm.h"
 
 /**
  * DOC: Xe GT Idle
@@ -40,6 +41,15 @@ static struct xe_guc_pc *gtidle_to_pc(struct xe_gt_idle *gtidle)
        return &gtidle_to_gt(gtidle)->uc.guc.pc;
 }
 
+static struct xe_device *
+pc_to_xe(struct xe_guc_pc *pc)
+{
+       struct xe_guc *guc = container_of(pc, struct xe_guc, pc);
+       struct xe_gt *gt = container_of(guc, struct xe_gt, uc.guc);
+
+       return gt_to_xe(gt);
+}
+
 static const char *gt_idle_state_to_string(enum xe_gt_idle_state state)
 {
        switch (state) {
@@ -86,8 +96,14 @@ static ssize_t name_show(struct device *dev,
                         struct device_attribute *attr, char *buff)
 {
        struct xe_gt_idle *gtidle = dev_to_gtidle(dev);
+       struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
+       ssize_t ret;
+
+       xe_pm_runtime_get(pc_to_xe(pc));
+       ret = sysfs_emit(buff, "%s\n", gtidle->name);
+       xe_pm_runtime_put(pc_to_xe(pc));
 
-       return sysfs_emit(buff, "%s\n", gtidle->name);
+       return ret;
 }
 static DEVICE_ATTR_RO(name);
 
@@ -98,7 +114,9 @@ static ssize_t idle_status_show(struct device *dev,
        struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
        enum xe_gt_idle_state state;
 
+       xe_pm_runtime_get(pc_to_xe(pc));
        state = gtidle->idle_status(pc);
+       xe_pm_runtime_put(pc_to_xe(pc));
 
        return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state));
 }
@@ -111,7 +129,10 @@ static ssize_t idle_residency_ms_show(struct device *dev,
        struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
        u64 residency;
 
+       xe_pm_runtime_get(pc_to_xe(pc));
        residency = gtidle->idle_residency(pc);
+       xe_pm_runtime_put(pc_to_xe(pc));
+
        return sysfs_emit(buff, "%llu\n", get_residency_ms(gtidle, residency));
 }
 static DEVICE_ATTR_RO(idle_residency_ms);
index 63d640591a527272e646ca3927b4ee3a6d71f137..9c33045ff1ef4082bf0e77f1992e6d5650ec6e8f 100644 (file)
@@ -11,6 +11,7 @@
 #include "xe_gt_sysfs.h"
 #include "xe_gt_throttle_sysfs.h"
 #include "xe_mmio.h"
+#include "xe_pm.h"
 
 /**
  * DOC: Xe GT Throttle
@@ -38,10 +39,12 @@ static u32 read_perf_limit_reasons(struct xe_gt *gt)
 {
        u32 reg;
 
+       xe_pm_runtime_get(gt_to_xe(gt));
        if (xe_gt_is_media_type(gt))
                reg = xe_mmio_read32(gt, MTL_MEDIA_PERF_LIMIT_REASONS);
        else
                reg = xe_mmio_read32(gt, GT0_PERF_LIMIT_REASONS);
+       xe_pm_runtime_put(gt_to_xe(gt));
 
        return reg;
 }
index 2345fb42fa39f072e7c5453159c54a22b1667e6d..9e23ca7f45ad0a442ce48bef9e8c5bb48201258c 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "xe_gt.h"
 #include "xe_hw_engine_class_sysfs.h"
+#include "xe_pm.h"
 
 #define MAX_ENGINE_CLASS_NAME_LEN    16
 static int xe_add_hw_engine_class_defaults(struct xe_device *xe,
@@ -513,6 +514,7 @@ kobj_xe_hw_engine_class(struct xe_device *xe, struct kobject *parent, char *name
                kobject_put(&keclass->base);
                return NULL;
        }
+       keclass->xe = xe;
 
        err = drmm_add_action_or_reset(&xe->drm, kobj_xe_hw_engine_class_fini,
                                       &keclass->base);
@@ -567,9 +569,63 @@ static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj)
        kfree(kobj);
 }
 
+#include "xe_pm.h"
+
+static inline struct xe_device *pdev_to_xe_device(struct pci_dev *pdev)
+{
+       return pci_get_drvdata(pdev);
+}
+
+static inline struct xe_device *to_xe_device(const struct drm_device *dev)
+{
+       return container_of(dev, struct xe_device, drm);
+}
+
+static ssize_t xe_hw_engine_class_sysfs_attr_show(struct kobject *kobj,
+                                                 struct attribute *attr,
+                                                 char *buf)
+{
+       struct xe_device *xe = kobj_to_xe(kobj);
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
+
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->show) {
+               xe_pm_runtime_get(xe);
+               ret = kattr->show(kobj, kattr, buf);
+               xe_pm_runtime_put(xe);
+       }
+
+       return ret;
+}
+
+static ssize_t xe_hw_engine_class_sysfs_attr_store(struct kobject *kobj,
+                                                  struct attribute *attr,
+                                                  const char *buf,
+                                                  size_t count)
+{
+       struct xe_device *xe = kobj_to_xe(kobj);
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
+
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->store) {
+               xe_pm_runtime_get(xe);
+               ret = kattr->store(kobj, kattr, buf, count);
+               xe_pm_runtime_put(xe);
+       }
+
+       return ret;
+}
+
+static const struct sysfs_ops xe_hw_engine_class_sysfs_ops = {
+       .show = xe_hw_engine_class_sysfs_attr_show,
+       .store = xe_hw_engine_class_sysfs_attr_store,
+};
+
 static const struct kobj_type xe_hw_engine_sysfs_kobj_type = {
        .release = xe_hw_engine_sysfs_kobj_release,
-       .sysfs_ops = &kobj_sysfs_ops,
+       .sysfs_ops = &xe_hw_engine_class_sysfs_ops,
 };
 
 static void hw_engine_class_sysfs_fini(struct drm_device *drm, void *arg)
index ec5ba673b314b766e1562eaf4392c63a476ce292..28a0d7c909c0143f9210066ca3d08742a607cfc2 100644 (file)
@@ -26,6 +26,8 @@ struct kobj_eclass {
        struct kobject base;
        /** @eclass: A pointer to the hw engine class interface */
        struct xe_hw_engine_class_intf *eclass;
+       /** @xe: A pointer to the xe device */
+       struct xe_device *xe;
 };
 
 static inline struct xe_hw_engine_class_intf *kobj_to_eclass(struct kobject *kobj)
@@ -33,4 +35,9 @@ static inline struct xe_hw_engine_class_intf *kobj_to_eclass(struct kobject *kob
        return container_of(kobj, struct kobj_eclass, base)->eclass;
 }
 
+static inline struct xe_device *kobj_to_xe(struct kobject *kobj)
+{
+       return container_of(kobj, struct kobj_eclass, base)->xe;
+}
+
 #endif
index 0662968d7bcbe617fc98ee31421caacaff688650..237a0761d3ad66365d8e30295c07954e7ba9b4e1 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/sysfs.h>
 #include <drm/drm_managed.h>
 
+#include "xe_pm.h"
 #include "xe_tile.h"
 #include "xe_tile_sysfs.h"
 #include "xe_vram_freq.h"