]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe: Implement xe_pagefault_init
authorMatthew Brost <matthew.brost@intel.com>
Fri, 31 Oct 2025 16:54:11 +0000 (09:54 -0700)
committerMatthew Brost <matthew.brost@intel.com>
Tue, 4 Nov 2025 17:04:26 +0000 (09:04 -0800)
Create pagefault queues and initialize them.

v2:
 - Fix kernel doc + add comment for number PF queue (Francois)
v4:
 - Move init after GT init (CI, Francois)

Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Francois Dugast <francois.dugast@intel.com>
Tested-by: Francois Dugast <francois.dugast@intel.com>
Link: https://patch.msgid.link/20251031165416.2871503-3-matthew.brost@intel.com
drivers/gpu/drm/xe/xe_device.c
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_pagefault.c

index 3db922dd2b247d8bb950621630db71a3837d0371..9f2f19dc1fd34a29b39e5423235cb6984614256d 100644 (file)
@@ -52,6 +52,7 @@
 #include "xe_nvm.h"
 #include "xe_oa.h"
 #include "xe_observation.h"
+#include "xe_pagefault.h"
 #include "xe_pat.h"
 #include "xe_pcode.h"
 #include "xe_pm.h"
@@ -896,6 +897,10 @@ int xe_device_probe(struct xe_device *xe)
                        return err;
        }
 
+       err = xe_pagefault_init(xe);
+       if (err)
+               return err;
+
        if (xe->tiles->media_gt &&
            XE_GT_WA(xe->tiles->media_gt, 15015404425_disable))
                XE_DEVICE_WA_DISABLE(xe, 15015404425);
index dc17f63f93533296b97bb2b8f2d4666329194651..a03cc83aa26fe38c53f0cfa13ffb74da2d1ad77b 100644 (file)
@@ -18,6 +18,7 @@
 #include "xe_lmtt_types.h"
 #include "xe_memirq_types.h"
 #include "xe_oa_types.h"
+#include "xe_pagefault_types.h"
 #include "xe_platform_types.h"
 #include "xe_pmu_types.h"
 #include "xe_pt_types.h"
@@ -413,6 +414,16 @@ struct xe_device {
                u32 next_asid;
                /** @usm.lock: protects UM state */
                struct rw_semaphore lock;
+               /** @usm.pf_wq: page fault work queue, unbound, high priority */
+               struct workqueue_struct *pf_wq;
+               /*
+                * We pick 4 here because, in the current implementation, it
+                * yields the best bandwidth utilization of the kernel paging
+                * engine.
+                */
+#define XE_PAGEFAULT_QUEUE_COUNT       4
+               /** @usm.pf_queue: Page fault queues */
+               struct xe_pagefault_queue pf_queue[XE_PAGEFAULT_QUEUE_COUNT];
        } usm;
 
        /** @pinned: pinned BO state */
index d509a80cb1f31d39f260bd010f85f5b01325658a..42952a91d1f567d7af5675d6ef58ba964142f233 100644 (file)
@@ -3,6 +3,10 @@
  * Copyright © 2025 Intel Corporation
  */
 
+#include <drm/drm_managed.h>
+
+#include "xe_device.h"
+#include "xe_gt_types.h"
 #include "xe_pagefault.h"
 #include "xe_pagefault_types.h"
 
  * xe_pagefault.c implements the consumer layer.
  */
 
+static int xe_pagefault_entry_size(void)
+{
+       /*
+        * Power of two alignment is not a hardware requirement, rather a
+        * software restriction which makes the math for page fault queue
+        * management simplier.
+        */
+       return roundup_pow_of_two(sizeof(struct xe_pagefault));
+}
+
+static void xe_pagefault_queue_work(struct work_struct *w)
+{
+       /* TODO: Implement */
+}
+
+static int xe_pagefault_queue_init(struct xe_device *xe,
+                                  struct xe_pagefault_queue *pf_queue)
+{
+       struct xe_gt *gt;
+       int total_num_eus = 0;
+       u8 id;
+
+       for_each_gt(gt, xe, id) {
+               xe_dss_mask_t all_dss;
+               int num_dss, num_eus;
+
+               bitmap_or(all_dss, gt->fuse_topo.g_dss_mask,
+                         gt->fuse_topo.c_dss_mask, XE_MAX_DSS_FUSE_BITS);
+
+               num_dss = bitmap_weight(all_dss, XE_MAX_DSS_FUSE_BITS);
+               num_eus = bitmap_weight(gt->fuse_topo.eu_mask_per_dss,
+                                       XE_MAX_EU_FUSE_BITS) * num_dss;
+
+               total_num_eus += num_eus;
+       }
+
+       xe_assert(xe, total_num_eus);
+
+       /*
+        * user can issue separate page faults per EU and per CS
+        *
+        * XXX: Multiplier required as compute UMD are getting PF queue errors
+        * without it. Follow on why this multiplier is required.
+        */
+#define PF_MULTIPLIER  8
+       pf_queue->size = (total_num_eus + XE_NUM_HW_ENGINES) *
+               xe_pagefault_entry_size() * PF_MULTIPLIER;
+       pf_queue->size = roundup_pow_of_two(pf_queue->size);
+#undef PF_MULTIPLIER
+
+       drm_dbg(&xe->drm, "xe_pagefault_entry_size=%d, total_num_eus=%d, pf_queue->size=%u",
+               xe_pagefault_entry_size(), total_num_eus, pf_queue->size);
+
+       spin_lock_init(&pf_queue->lock);
+       INIT_WORK(&pf_queue->worker, xe_pagefault_queue_work);
+
+       pf_queue->data = drmm_kzalloc(&xe->drm, pf_queue->size, GFP_KERNEL);
+       if (!pf_queue->data)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void xe_pagefault_fini(void *arg)
+{
+       struct xe_device *xe = arg;
+
+       destroy_workqueue(xe->usm.pf_wq);
+}
+
 /**
  * xe_pagefault_init() - Page fault init
  * @xe: xe device instance
  */
 int xe_pagefault_init(struct xe_device *xe)
 {
-       /* TODO - implement */
-       return 0;
+       int err, i;
+
+       if (!xe->info.has_usm)
+               return 0;
+
+       xe->usm.pf_wq = alloc_workqueue("xe_page_fault_work_queue",
+                                       WQ_UNBOUND | WQ_HIGHPRI,
+                                       XE_PAGEFAULT_QUEUE_COUNT);
+       if (!xe->usm.pf_wq)
+               return -ENOMEM;
+
+       for (i = 0; i < XE_PAGEFAULT_QUEUE_COUNT; ++i) {
+               err = xe_pagefault_queue_init(xe, xe->usm.pf_queue + i);
+               if (err)
+                       goto err_out;
+       }
+
+       return devm_add_action_or_reset(xe->drm.dev, xe_pagefault_fini, xe);
+
+err_out:
+       destroy_workqueue(xe->usm.pf_wq);
+       return err;
 }
 
 /**