--- /dev/null
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2024 Intel Corporation
+ */
+
+#include <linux/debugfs.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_debugfs.h>
+
+#include "xe_bo.h"
+#include "xe_debugfs.h"
+#include "xe_device.h"
+#include "xe_gt.h"
+#include "xe_gt_debugfs.h"
+#include "xe_gt_sriov_pf_config.h"
+#include "xe_gt_sriov_pf_debugfs.h"
+#include "xe_gt_sriov_pf_helpers.h"
+#include "xe_pm.h"
+
+/*
+ *      /sys/kernel/debug/dri/0/
+ *      ├── gt0          # d_inode->i_private = gt
+ *      │   ├── pf   # d_inode->i_private = gt
+ *      │   ├── vf1  # d_inode->i_private = VFID(1)
+ *      :   :
+ *      │   ├── vfN  # d_inode->i_private = VFID(N)
+ */
+
+static void *extract_priv(struct dentry *d)
+{
+       return d->d_inode->i_private;
+}
+
+static struct xe_gt *extract_gt(struct dentry *d)
+{
+       return extract_priv(d->d_parent);
+}
+
+static unsigned int extract_vfid(struct dentry *d)
+{
+       return extract_priv(d) == extract_gt(d) ? PFID : (uintptr_t)extract_priv(d);
+}
+
+/*
+ *      /sys/kernel/debug/dri/0/
+ *      ├── gt0
+ *      │   ├── pf
+ *      │   │   ├── ggtt_available
+ *      │   │   ├── ggtt_provisioned
+ *      │   │   ├── contexts_provisioned
+ *      │   │   ├── doorbells_provisioned
+ */
+
+static const struct drm_info_list pf_info[] = {
+       {
+               "ggtt_available",
+               .show = xe_gt_debugfs_simple_show,
+               .data = xe_gt_sriov_pf_config_print_available_ggtt,
+       },
+       {
+               "ggtt_provisioned",
+               .show = xe_gt_debugfs_simple_show,
+               .data = xe_gt_sriov_pf_config_print_ggtt,
+       },
+       {
+               "contexts_provisioned",
+               .show = xe_gt_debugfs_simple_show,
+               .data = xe_gt_sriov_pf_config_print_ctxs,
+       },
+       {
+               "doorbells_provisioned",
+               .show = xe_gt_debugfs_simple_show,
+               .data = xe_gt_sriov_pf_config_print_dbs,
+       },
+};
+
+/*
+ *      /sys/kernel/debug/dri/0/
+ *      ├── gt0
+ *      │   ├── pf
+ *      │   │   ├── ggtt_spare
+ *      │   │   ├── lmem_spare
+ *      │   │   ├── doorbells_spare
+ *      │   │   ├── contexts_spare
+ *      │   │   ├── exec_quantum_ms
+ *      │   │   ├── preempt_timeout_us
+ *      │   ├── vf1
+ *      │   │   ├── ggtt_quota
+ *      │   │   ├── lmem_quota
+ *      │   │   ├── doorbells_quota
+ *      │   │   ├── contexts_quota
+ *      │   │   ├── exec_quantum_ms
+ *      │   │   ├── preempt_timeout_us
+ */
+
+#define DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(CONFIG, TYPE, FORMAT)         \
+                                                                               \
+static int CONFIG##_set(void *data, u64 val)                                   \
+{                                                                              \
+       struct xe_gt *gt = extract_gt(data);                                    \
+       unsigned int vfid = extract_vfid(data);                                 \
+       struct xe_device *xe = gt_to_xe(gt);                                    \
+       int err;                                                                \
+                                                                               \
+       if (val > (TYPE)~0ull)                                                  \
+               return -EOVERFLOW;                                              \
+                                                                               \
+       xe_pm_runtime_get(xe);                                                  \
+       err = xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val);                \
+       xe_pm_runtime_put(xe);                                                  \
+                                                                               \
+       return err;                                                             \
+}                                                                              \
+                                                                               \
+static int CONFIG##_get(void *data, u64 *val)                                  \
+{                                                                              \
+       struct xe_gt *gt = extract_gt(data);                                    \
+       unsigned int vfid = extract_vfid(data);                                 \
+                                                                               \
+       *val = xe_gt_sriov_pf_config_get_##CONFIG(gt, vfid);                    \
+       return 0;                                                               \
+}                                                                              \
+                                                                               \
+DEFINE_DEBUGFS_ATTRIBUTE(CONFIG##_fops, CONFIG##_get, CONFIG##_set, FORMAT)
+
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(ggtt, u64, "%llu\n");
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(lmem, u64, "%llu\n");
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(ctxs, u32, "%llu\n");
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(dbs, u32, "%llu\n");
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(exec_quantum, u32, "%llu\n");
+DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(preempt_timeout, u32, "%llu\n");
+
+static void pf_add_config_attrs(struct xe_gt *gt, struct dentry *parent, unsigned int vfid)
+{
+       xe_gt_assert(gt, gt == extract_gt(parent));
+       xe_gt_assert(gt, vfid == extract_vfid(parent));
+
+       if (!xe_gt_is_media_type(gt)) {
+               debugfs_create_file_unsafe(vfid ? "ggtt_quota" : "ggtt_spare",
+                                          0644, parent, parent, &ggtt_fops);
+               if (IS_DGFX(gt_to_xe(gt)))
+                       debugfs_create_file_unsafe(vfid ? "lmem_quota" : "lmem_spare",
+                                                  0644, parent, parent, &lmem_fops);
+       }
+       debugfs_create_file_unsafe(vfid ? "doorbells_quota" : "doorbells_spare",
+                                  0644, parent, parent, &dbs_fops);
+       debugfs_create_file_unsafe(vfid ? "contexts_quota" : "contexts_spare",
+                                  0644, parent, parent, &ctxs_fops);
+       debugfs_create_file_unsafe("exec_quantum_ms", 0644, parent, parent,
+                                  &exec_quantum_fops);
+       debugfs_create_file_unsafe("preempt_timeout_us", 0644, parent, parent,
+                                  &preempt_timeout_fops);
+}
+
+/**
+ * xe_gt_sriov_pf_debugfs_register - Register SR-IOV PF specific entries in GT debugfs.
+ * @gt: the &xe_gt to register
+ * @root: the &dentry that represents the GT directory
+ *
+ * Register SR-IOV PF entries that are GT related and must be shown under GT debugfs.
+ */
+void xe_gt_sriov_pf_debugfs_register(struct xe_gt *gt, struct dentry *root)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+       struct drm_minor *minor = xe->drm.primary;
+       int n, totalvfs = xe_sriov_pf_get_totalvfs(xe);
+       struct dentry *pfdentry;
+       struct dentry *vfdentry;
+       char buf[14]; /* should be enough up to "vf%u\0" for 2^32 - 1 */
+
+       xe_gt_assert(gt, IS_SRIOV_PF(xe));
+       xe_gt_assert(gt, root->d_inode->i_private == gt);
+
+       /*
+        *      /sys/kernel/debug/dri/0/
+        *      ├── gt0
+        *      │   ├── pf
+        */
+       pfdentry = debugfs_create_dir("pf", root);
+       if (IS_ERR(pfdentry))
+               return;
+       pfdentry->d_inode->i_private = gt;
+
+       drm_debugfs_create_files(pf_info, ARRAY_SIZE(pf_info), pfdentry, minor);
+       pf_add_config_attrs(gt, pfdentry, PFID);
+
+       for (n = 1; n <= totalvfs; n++) {
+               /*
+                *      /sys/kernel/debug/dri/0/
+                *      ├── gt0
+                *      │   ├── vf1
+                *      │   ├── vf2
+                */
+               snprintf(buf, sizeof(buf), "vf%u", n);
+               vfdentry = debugfs_create_dir(buf, root);
+               if (IS_ERR(vfdentry))
+                       break;
+               vfdentry->d_inode->i_private = (void *)(uintptr_t)n;
+
+               pf_add_config_attrs(gt, vfdentry, VFID(n));
+       }
+}