]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/xe: Use topology to determine page fault queue size
authorStuart Summers <stuart.summers@intel.com>
Sat, 17 Aug 2024 02:47:31 +0000 (02:47 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Oct 2024 10:00:37 +0000 (12:00 +0200)
[ Upstream commit 3338e4f90c143cf32f77d64f464cb7f2c2d24700 ]

Currently the page fault queue size is hard coded. However
the hardware supports faulting for each EU and each CS.
For some applications running on hardware with a large
number of EUs and CSs, this can result in an overflow of
the page fault queue.

Add a small calculation to determine the page fault queue
size based on the number of EUs and CSs in the platform as
detmined by fuses.

Signed-off-by: Stuart Summers <stuart.summers@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/24d582a3b48c97793b8b6a402f34b4b469471636.1723862633.git.stuart.summers@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/xe/xe_gt_pagefault.c
drivers/gpu/drm/xe/xe_gt_types.h

index 67e8efcaa93f1c9ee0a806412fb5c2856fa3e9a1..ee78b4e47dfcb87e89002716cea0b0161084750f 100644 (file)
@@ -307,7 +307,7 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf)
                        PFD_VIRTUAL_ADDR_LO_SHIFT;
 
                pf_queue->tail = (pf_queue->tail + PF_MSG_LEN_DW) %
-                       PF_QUEUE_NUM_DW;
+                       pf_queue->num_dw;
                ret = true;
        }
        spin_unlock_irq(&pf_queue->lock);
@@ -319,7 +319,8 @@ static bool pf_queue_full(struct pf_queue *pf_queue)
 {
        lockdep_assert_held(&pf_queue->lock);
 
-       return CIRC_SPACE(pf_queue->head, pf_queue->tail, PF_QUEUE_NUM_DW) <=
+       return CIRC_SPACE(pf_queue->head, pf_queue->tail,
+                         pf_queue->num_dw) <=
                PF_MSG_LEN_DW;
 }
 
@@ -332,22 +333,23 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len)
        u32 asid;
        bool full;
 
-       /*
-        * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
-        */
-       BUILD_BUG_ON(PF_QUEUE_NUM_DW % PF_MSG_LEN_DW);
-
        if (unlikely(len != PF_MSG_LEN_DW))
                return -EPROTO;
 
        asid = FIELD_GET(PFD_ASID, msg[1]);
        pf_queue = gt->usm.pf_queue + (asid % NUM_PF_QUEUE);
 
+       /*
+        * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
+        */
+       xe_gt_assert(gt, !(pf_queue->num_dw % PF_MSG_LEN_DW));
+
        spin_lock_irqsave(&pf_queue->lock, flags);
        full = pf_queue_full(pf_queue);
        if (!full) {
                memcpy(pf_queue->data + pf_queue->head, msg, len * sizeof(u32));
-               pf_queue->head = (pf_queue->head + len) % PF_QUEUE_NUM_DW;
+               pf_queue->head = (pf_queue->head + len) %
+                       pf_queue->num_dw;
                queue_work(gt->usm.pf_wq, &pf_queue->worker);
        } else {
                drm_warn(&xe->drm, "PF Queue full, shouldn't be possible");
@@ -406,26 +408,54 @@ static void pagefault_fini(void *arg)
 {
        struct xe_gt *gt = arg;
        struct xe_device *xe = gt_to_xe(gt);
+       int i;
 
        if (!xe->info.has_usm)
                return;
 
        destroy_workqueue(gt->usm.acc_wq);
        destroy_workqueue(gt->usm.pf_wq);
+
+       for (i = 0; i < NUM_PF_QUEUE; ++i)
+               kfree(gt->usm.pf_queue[i].data);
+}
+
+static int xe_alloc_pf_queue(struct xe_gt *gt, struct pf_queue *pf_queue)
+{
+       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;
+
+       /* user can issue separate page faults per EU and per CS */
+       pf_queue->num_dw =
+               (num_eus + XE_NUM_HW_ENGINES) * PF_MSG_LEN_DW;
+
+       pf_queue->gt = gt;
+       pf_queue->data = kzalloc(pf_queue->num_dw, GFP_KERNEL);
+       spin_lock_init(&pf_queue->lock);
+       INIT_WORK(&pf_queue->worker, pf_queue_work_func);
+
+       return 0;
 }
 
 int xe_gt_pagefault_init(struct xe_gt *gt)
 {
        struct xe_device *xe = gt_to_xe(gt);
-       int i;
+       int i, ret = 0;
 
        if (!xe->info.has_usm)
                return 0;
 
        for (i = 0; i < NUM_PF_QUEUE; ++i) {
-               gt->usm.pf_queue[i].gt = gt;
-               spin_lock_init(&gt->usm.pf_queue[i].lock);
-               INIT_WORK(&gt->usm.pf_queue[i].worker, pf_queue_work_func);
+               ret = xe_alloc_pf_queue(gt, &gt->usm.pf_queue[i]);
+               if (ret)
+                       return ret;
        }
        for (i = 0; i < NUM_ACC_QUEUE; ++i) {
                gt->usm.acc_queue[i].gt = gt;
index cfdc761ff7f46bdaae9d512afd63ffa853fd27cb..2dbea50cd8f98ec82b88ea990399d8fae34c2cfb 100644 (file)
@@ -229,9 +229,14 @@ struct xe_gt {
                struct pf_queue {
                        /** @usm.pf_queue.gt: back pointer to GT */
                        struct xe_gt *gt;
-#define PF_QUEUE_NUM_DW        128
                        /** @usm.pf_queue.data: data in the page fault queue */
-                       u32 data[PF_QUEUE_NUM_DW];
+                       u32 *data;
+                       /**
+                        * @usm.pf_queue.num_dw: number of DWORDS in the page
+                        * fault queue. Dynamically calculated based on the number
+                        * of compute resources available.
+                        */
+                       u32 num_dw;
                        /**
                         * @usm.pf_queue.tail: tail pointer in DWs for page fault queue,
                         * moved by worker which processes faults (consumer).