From: "Piórkowski, Piotr" <piotr.piorkowski@intel.com>
To: <intel-xe@lists.freedesktop.org>
Cc: "Piotr Piórkowski" <piotr.piorkowski@intel.com>,
"Michal Wajdeczko" <michal.wajdeczko@intel.com>,
"Ville Syrjälä" <ville.syrjala@linux.intel.com>,
"Maarten Lankhorst" <dev@lankhorst.se>
Subject: [PATCH v5 2/4] drm/xe/ggtt: Split GGTT into usable and shareable pools
Date: Tue, 8 Sep 2026 12:06:00 +0200 [thread overview]
Message-ID: <20260908100602.1626556-3-piotr.piorkowski@intel.com> (raw)
In-Reply-To: <20260908100602.1626556-1-piotr.piorkowski@intel.com>
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
Driver-owned GGTT allocations and VF provisioning currently use a single
GGTT pool. Split it into a usable pool for driver-owned allocations and a
shareable pool for VF provisioning.
The pools are separate logical ranges and may overlap, but allocations are
limited to the configured size of their corresponding pool. Allocate from
the bottom of the usable pool and from the top of the shareable pool when a
shareable pool is present.
Add separate insertion APIs for the usable and shareable pools.
v2:
- Rename ggtt->usable_size back to ggtt->size.
- Remove the ggtt_insert_node_in_range() helper.
v3:
- Introduce the full_size struct field instead of the ggtt_accessible_size
function.
v4:
- Set the shareable pool size only for SR-IOV PF,
- Return -ENOSPC instead of asserting when a large BO no longer fits after
end is clamped to ggtt->size.
v5:
- Move range initializer rename and full_size parameter here.
- Use shareable_size and compute the shareable start on demand.
- Constrain regular allocations to the usable pool.
Assisted-by: Claude:claude-5-sonnet
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Maarten Lankhorst <dev@lankhorst.se>
---
drivers/gpu/drm/xe/xe_ggtt.c | 166 +++++++++++++++++++++++++++++------
drivers/gpu/drm/xe/xe_ggtt.h | 4 +
2 files changed, 143 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index c54a4cf967df9..6a59fc20153bf 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -144,8 +144,19 @@ struct xe_ggtt {
unsigned int access_count;
/** @wq: Dedicated unordered work queue to process node removals */
struct workqueue_struct *wq;
+#ifdef CONFIG_PCI_IOV
+ /** @shareable_size: Size of the GGTT range reserved for sharing with VFs */
+ u64 shareable_size;
+#endif
};
+#ifdef CONFIG_PCI_IOV
+static inline u64 ggtt_shareable_start(struct xe_ggtt *ggtt)
+{
+ return ggtt->full_size - ggtt->shareable_size;
+}
+#endif
+
static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index)
{
u64 pte = XE_PAGE_PRESENT;
@@ -357,17 +368,30 @@ static const struct xe_ggtt_pt_ops xelpg_pt_wa_ops = {
.ggtt_get_pte = xe_ggtt_get_pte,
};
-static void __xe_ggtt_init_early(struct xe_ggtt *ggtt, u64 start, u64 size)
+static void ggtt_init_ranges(struct xe_ggtt *ggtt, u64 start, u64 full_size,
+ u64 usable_size, u64 shareable_size)
{
+ struct xe_gt *gt = ggtt->tile->primary_gt;
+
+ xe_gt_assert(gt, full_size);
+ xe_gt_assert(gt, usable_size);
+ xe_gt_assert(gt, usable_size <= full_size);
+ xe_gt_assert(gt, shareable_size <= full_size);
+
ggtt->start = start;
- ggtt->full_size = size;
- ggtt->size = size;
- drm_mm_init(&ggtt->mm, 0, size);
+ ggtt->full_size = full_size;
+ ggtt->size = usable_size;
+
+#ifdef CONFIG_PCI_IOV
+ if (shareable_size)
+ ggtt->shareable_size = shareable_size;
+#endif
+ drm_mm_init(&ggtt->mm, 0, ggtt->full_size);
}
int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size)
{
- __xe_ggtt_init_early(ggtt, start, size);
+ ggtt_init_ranges(ggtt, start, size, size, 0);
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(xe_ggtt_init_kunit);
@@ -442,7 +466,8 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
if (!ggtt->wq)
return -ENOMEM;
- __xe_ggtt_init_early(ggtt, ggtt_start, ggtt_size);
+ ggtt_init_ranges(ggtt, ggtt_start, ggtt_size, ggtt_size,
+ IS_SRIOV_PF(xe) ? ggtt_size : 0);
err = drmm_add_action_or_reset(&xe->drm, ggtt_fini_early, ggtt);
if (err)
@@ -636,6 +661,11 @@ static void xe_ggtt_invalidate_engine(struct xe_ggtt *ggtt)
ggtt_invalidate_gt_engine_tlb(ggtt->tile->media_gt);
}
+static inline u64 xe_ggtt_bottom(struct xe_ggtt *ggtt)
+{
+ return xe_wopcm_size(tile_to_xe(ggtt->tile));
+}
+
/**
* xe_ggtt_shift_nodes() - Shift GGTT nodes to adjust for a change in usable address range.
* @ggtt: the &xe_ggtt struct instance
@@ -647,24 +677,63 @@ static void xe_ggtt_invalidate_engine(struct xe_ggtt *ggtt)
* This function may be called multiple times during recovery, but if
* @new_start is unchanged from the current base, it's a noop.
*
- * @new_start should be a value between xe_wopcm_size() and #GUC_GGTT_TOP.
+ * @new_start should be a value between the GGTT bottom and #GUC_GGTT_TOP.
*/
void xe_ggtt_shift_nodes(struct xe_ggtt *ggtt, u64 new_start)
{
guard(mutex)(&ggtt->lock);
- xe_tile_assert(ggtt->tile, new_start >= xe_wopcm_size(tile_to_xe(ggtt->tile)));
+ xe_tile_assert(ggtt->tile, new_start >= xe_ggtt_bottom(ggtt));
xe_tile_assert(ggtt->tile, new_start + ggtt->size <= GUC_GGTT_TOP);
+#ifdef CONFIG_PCI_IOV
+ xe_tile_assert(ggtt->tile, ggtt->shareable_size == 0);
+#endif
/* pairs with READ_ONCE in xe_ggtt_node_addr() */
WRITE_ONCE(ggtt->start, new_start);
}
-static int xe_ggtt_insert_node_locked(struct xe_ggtt_node *node,
- u32 size, u32 align, u32 mm_flags)
+static int ggtt_insert_node_in_range_locked(struct xe_ggtt_node *node, u32 size,
+ u32 align, u64 range_start,
+ u64 range_size, u32 mm_flags)
+{
+ struct xe_ggtt *ggtt = node->ggtt;
+ u64 range_end = range_start + range_size;
+
+ lockdep_assert_held(&ggtt->lock);
+
+ if (!range_size || range_end <= range_start)
+ return -EINVAL;
+
+ if (range_end > ggtt->full_size)
+ return -ERANGE;
+
+ if (size > range_size)
+ return -ENOSPC;
+
+ return drm_mm_insert_node_in_range(&ggtt->mm, &node->base, size, align, 0,
+ range_start, range_end, mm_flags);
+}
+
+/*
+ * When the shareable range is present, allocations start from the bottom
+ * to leave space at the top; otherwise they start from the top.
+ */
+static u32 ggtt_usable_insert_flags(struct xe_ggtt *ggtt)
{
- return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0,
- mm_flags);
+#ifdef CONFIG_PCI_IOV
+ if (ggtt->shareable_size > 0)
+ return DRM_MM_INSERT_LOW;
+#endif
+ return DRM_MM_INSERT_HIGH;
+}
+
+static int xe_ggtt_insert_node_locked(struct xe_ggtt_node *node, u32 size, u32 align)
+{
+ struct xe_ggtt *ggtt = node->ggtt;
+
+ return ggtt_insert_node_in_range_locked(node, size, align, 0,
+ ggtt->size, ggtt_usable_insert_flags(ggtt));
}
static struct xe_ggtt_node *ggtt_node_init(struct xe_ggtt *ggtt)
@@ -681,12 +750,12 @@ static struct xe_ggtt_node *ggtt_node_init(struct xe_ggtt *ggtt)
}
/**
- * xe_ggtt_insert_node - Insert a &xe_ggtt_node into the GGTT
+ * xe_ggtt_insert_node() - Insert a &xe_ggtt_node into the GGTT
* @ggtt: the &xe_ggtt into which the node should be inserted.
* @size: size of the node
* @align: alignment constrain of the node
*
- * Return: &xe_ggtt_node on success or a ERR_PTR on failure.
+ * Return: &xe_ggtt_node on success or an ERR_PTR on failure.
*/
struct xe_ggtt_node *xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 align)
{
@@ -698,8 +767,45 @@ struct xe_ggtt_node *xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 ali
return node;
guard(mutex)(&ggtt->lock);
- ret = xe_ggtt_insert_node_locked(node, size, align,
- DRM_MM_INSERT_HIGH);
+
+ ret = xe_ggtt_insert_node_locked(node, size, align);
+ if (ret) {
+ ggtt_node_fini(node);
+ return ERR_PTR(ret);
+ }
+
+ return node;
+}
+
+#ifdef CONFIG_PCI_IOV
+/**
+ * xe_ggtt_insert_node_shareable() - Insert a new node in the shareable GGTT range
+ * @ggtt: the &xe_ggtt into which the node should be inserted.
+ * @size: size of the node
+ * @align: alignment constrain of the node
+ *
+ * Allocations always start from the top (DRM_MM_INSERT_HIGH).
+ *
+ * Return: &xe_ggtt_node on success or an ERR_PTR on failure.
+ */
+struct xe_ggtt_node *xe_ggtt_insert_node_shareable(struct xe_ggtt *ggtt, u32 size, u32 align)
+{
+ struct xe_ggtt_node *node;
+ int ret;
+
+ if (!ggtt->shareable_size)
+ return ERR_PTR(-ENOSPC);
+
+ node = ggtt_node_init(ggtt);
+ if (IS_ERR(node))
+ return node;
+
+ guard(mutex)(&ggtt->lock);
+
+ ret = ggtt_insert_node_in_range_locked(node, size, align,
+ ggtt_shareable_start(ggtt),
+ ggtt->shareable_size,
+ DRM_MM_INSERT_HIGH);
if (ret) {
ggtt_node_fini(node);
return ERR_PTR(ret);
@@ -707,6 +813,7 @@ struct xe_ggtt_node *xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 ali
return node;
}
+#endif
/**
* xe_ggtt_node_pt_size() - Get the size of page table entries needed to map a GGTT node.
@@ -790,6 +897,7 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
*
* This function allows inserting a GGTT node with a custom transformation function.
* This is useful for display to allow inserting rotated framebuffers to GGTT.
+ * Allocates from the usable range only.
*
* Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
*/
@@ -810,7 +918,7 @@ struct xe_ggtt_node *xe_ggtt_insert_node_transform(struct xe_ggtt *ggtt,
goto err;
}
- ret = xe_ggtt_insert_node_locked(node, size, align, 0);
+ ret = xe_ggtt_insert_node_locked(node, size, align);
if (ret)
goto err_unlock;
@@ -832,6 +940,7 @@ struct xe_ggtt_node *xe_ggtt_insert_node_transform(struct xe_ggtt *ggtt,
static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
u64 start, u64 end, struct drm_exec *exec)
{
+ struct xe_device *xe = tile_to_xe(ggtt->tile);
u64 alignment = bo->min_align > 0 ? bo->min_align : XE_PAGE_SIZE;
u8 tile_id = ggtt->tile->id;
int err;
@@ -849,16 +958,16 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
if (err)
return err;
- xe_pm_runtime_get_noresume(tile_to_xe(ggtt->tile));
+ guard(xe_pm_runtime_noresume)(xe);
bo->ggtt_node[tile_id] = ggtt_node_init(ggtt);
if (IS_ERR(bo->ggtt_node[tile_id])) {
err = PTR_ERR(bo->ggtt_node[tile_id]);
bo->ggtt_node[tile_id] = NULL;
- goto out;
+ return err;
}
- mutex_lock(&ggtt->lock);
+ guard(mutex)(&ggtt->lock);
/*
* When inheriting the initial framebuffer, the framebuffer is
* physically located at VRAM address 0, and usually at GGTT address 0 too.
@@ -877,28 +986,31 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
else
end = 0;
- xe_tile_assert(ggtt->tile, end >= start + xe_bo_size(bo));
+ end = min(end, ggtt->size);
+
+ if (end < start + xe_bo_size(bo)) {
+ ggtt_node_fini(bo->ggtt_node[tile_id]);
+ bo->ggtt_node[tile_id] = NULL;
+ return -ENOSPC;
+ }
err = drm_mm_insert_node_in_range(&ggtt->mm, &bo->ggtt_node[tile_id]->base,
- xe_bo_size(bo), alignment, 0, start, end, 0);
+ xe_bo_size(bo), alignment, 0, start, end,
+ ggtt_usable_insert_flags(ggtt));
if (err) {
ggtt_node_fini(bo->ggtt_node[tile_id]);
bo->ggtt_node[tile_id] = NULL;
} else {
u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
- u16 pat_index = xe_cache_pat_idx(tile_to_xe(ggtt->tile), cache_mode);
+ u16 pat_index = xe_cache_pat_idx(xe, cache_mode);
u64 pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index);
xe_ggtt_map_bo(ggtt, bo->ggtt_node[tile_id], bo, pte);
}
- mutex_unlock(&ggtt->lock);
if (!err && bo->flags & XE_BO_FLAG_GGTT_INVALIDATE)
xe_ggtt_invalidate(ggtt);
-out:
- xe_pm_runtime_put(tile_to_xe(ggtt->tile));
-
return err;
}
diff --git a/drivers/gpu/drm/xe/xe_ggtt.h b/drivers/gpu/drm/xe/xe_ggtt.h
index c864cc975a695..59b2f02870195 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.h
+++ b/drivers/gpu/drm/xe/xe_ggtt.h
@@ -24,6 +24,10 @@ u64 xe_ggtt_size(struct xe_ggtt *ggtt);
struct xe_ggtt_node *
xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 align);
+#ifdef CONFIG_PCI_IOV
+struct xe_ggtt_node *
+xe_ggtt_insert_node_shareable(struct xe_ggtt *ggtt, u32 size, u32 align);
+#endif
struct xe_ggtt_node *
xe_ggtt_insert_node_transform(struct xe_ggtt *ggtt,
struct xe_bo *bo, u64 pte,
--
2.34.1
next prev parent reply other threads:[~2026-09-08 10:06 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 10:05 [PATCH v5 0/4] Separate GGTT pools for submissions and VFs provisioning Piórkowski, Piotr
2026-09-08 10:05 ` [PATCH v5 1/4] drm/xe/ggtt: Introduce full GGTT range size Piórkowski, Piotr
2026-09-08 10:06 ` Piórkowski, Piotr [this message]
2026-09-08 10:06 ` [PATCH v5 3/4] drm/xe/ggtt: Initialize GGTT pools by SR-IOV mode Piórkowski, Piotr
2026-09-08 10:06 ` [PATCH v5 4/4] drm/xe/ggtt: Add KUnit tests for usable and shareable pools Piórkowski, Piotr
2026-09-08 10:27 ` sashiko-bot
2026-09-08 11:46 ` ✗ CI.checkpatch: warning for Separate GGTT pools for submissions and VFs provisioning (rev5) Patchwork
2026-09-08 11:48 ` ✓ CI.KUnit: success " Patchwork
2026-09-08 12:53 ` ✓ Xe.CI.BAT: " Patchwork
2026-09-08 15:44 ` ✗ Xe.CI.FULL: failure " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260908100602.1626556-3-piotr.piorkowski@intel.com \
--to=piotr.piorkowski@intel.com \
--cc=dev@lankhorst.se \
--cc=intel-xe@lists.freedesktop.org \
--cc=michal.wajdeczko@intel.com \
--cc=ville.syrjala@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox