Page accounting can change via the shrinker without calling xe_ttm_tt_unpopulate(), but those paths already update accounting through the xe_ttm_tt_account_*() helpers.
Move the page count tracepoints into xe_ttm_tt_account_add() and xe_ttm_tt_account_subtract() so accounting updates are recorded consistently, regardless of whether pages are populated, unpopulated, or reclaimed via the shrinker.
This avoids missing page count updates and keeps global accounting balanced across all TT lifecycle paths.
Cc: stable@vger.kernel.org Fixes: ce3d39fae3d3 ("drm/xe/bo: add GPU memory trace points") Signed-off-by: Matthew Brost matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8b6474cd3eaf..33afaee38f48 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -432,6 +432,9 @@ struct sg_table *xe_bo_sg(struct xe_bo *bo) return xe_tt->sg; }
+static void update_global_total_pages(struct ttm_device *ttm_dev, + long num_pages); + /* * Account ttm pages against the device shrinker's shrinkable and * purgeable counts. @@ -440,6 +443,7 @@ static void xe_ttm_tt_account_add(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
+ update_global_total_pages(&xe->ttm, tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, tt->num_pages); else @@ -450,6 +454,7 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
+ update_global_total_pages(&xe->ttm, -(long)tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, -(long)tt->num_pages); else @@ -575,7 +580,6 @@ static int xe_ttm_tt_populate(struct ttm_device *ttm_dev, struct ttm_tt *tt,
xe_tt->purgeable = false; xe_ttm_tt_account_add(ttm_to_xe_device(ttm_dev), tt); - update_global_total_pages(ttm_dev, tt->num_pages);
return 0; } @@ -592,7 +596,6 @@ static void xe_ttm_tt_unpopulate(struct ttm_device *ttm_dev, struct ttm_tt *tt)
ttm_pool_free(&ttm_dev->pool, tt); xe_ttm_tt_account_subtract(xe, tt); - update_global_total_pages(ttm_dev, -(long)tt->num_pages); }
static void xe_ttm_tt_destroy(struct ttm_device *ttm_dev, struct ttm_tt *tt)
Tested-by: Arselan Alvi arselan.alvi@intel.com
________________________________________ From: Brost, Matthew matthew.brost@intel.com Sent: Tuesday, January 6, 2026 4:21 PM To: intel-xe@lists.freedesktop.org Cc: Alvi, Arselan; stable@vger.kernel.org Subject: [PATCH] drm/xe: Tie page count tracepoints to TTM accounting functions
Page accounting can change via the shrinker without calling xe_ttm_tt_unpopulate(), but those paths already update accounting through the xe_ttm_tt_account_*() helpers.
Move the page count tracepoints into xe_ttm_tt_account_add() and xe_ttm_tt_account_subtract() so accounting updates are recorded consistently, regardless of whether pages are populated, unpopulated, or reclaimed via the shrinker.
This avoids missing page count updates and keeps global accounting balanced across all TT lifecycle paths.
Cc: stable@vger.kernel.org Fixes: ce3d39fae3d3 ("drm/xe/bo: add GPU memory trace points") Signed-off-by: Matthew Brost matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8b6474cd3eaf..33afaee38f48 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -432,6 +432,9 @@ struct sg_table *xe_bo_sg(struct xe_bo *bo) return xe_tt->sg; }
+static void update_global_total_pages(struct ttm_device *ttm_dev, + long num_pages); + /* * Account ttm pages against the device shrinker's shrinkable and * purgeable counts. @@ -440,6 +443,7 @@ static void xe_ttm_tt_account_add(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
+ update_global_total_pages(&xe->ttm, tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, tt->num_pages); else @@ -450,6 +454,7 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
+ update_global_total_pages(&xe->ttm, -(long)tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, -(long)tt->num_pages); else @@ -575,7 +580,6 @@ static int xe_ttm_tt_populate(struct ttm_device *ttm_dev, struct ttm_tt *tt,
xe_tt->purgeable = false; xe_ttm_tt_account_add(ttm_to_xe_device(ttm_dev), tt); - update_global_total_pages(ttm_dev, tt->num_pages);
return 0; } @@ -592,7 +596,6 @@ static void xe_ttm_tt_unpopulate(struct ttm_device *ttm_dev, struct ttm_tt *tt)
ttm_pool_free(&ttm_dev->pool, tt); xe_ttm_tt_account_subtract(xe, tt); - update_global_total_pages(ttm_dev, -(long)tt->num_pages); }
static void xe_ttm_tt_destroy(struct ttm_device *ttm_dev, struct ttm_tt *tt) -- 2.34.1
On Tue, 2026-01-06 at 16:21 -0800, Matthew Brost wrote:
Page accounting can change via the shrinker without calling xe_ttm_tt_unpopulate(), but those paths already update accounting through the xe_ttm_tt_account_*() helpers.
I see this is getting also called through the xe_bo_pin/unpin functions with a check for ttm_tt_is_populated(). Does that mean after this change we'd get a double accounting in those cases?
Thanks, Stuart
Move the page count tracepoints into xe_ttm_tt_account_add() and xe_ttm_tt_account_subtract() so accounting updates are recorded consistently, regardless of whether pages are populated, unpopulated, or reclaimed via the shrinker.
This avoids missing page count updates and keeps global accounting balanced across all TT lifecycle paths.
Cc: stable@vger.kernel.org Fixes: ce3d39fae3d3 ("drm/xe/bo: add GPU memory trace points") Signed-off-by: Matthew Brost matthew.brost@intel.com
drivers/gpu/drm/xe/xe_bo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8b6474cd3eaf..33afaee38f48 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -432,6 +432,9 @@ struct sg_table *xe_bo_sg(struct xe_bo *bo) return xe_tt->sg; } +static void update_global_total_pages(struct ttm_device *ttm_dev, + long num_pages);
/* * Account ttm pages against the device shrinker's shrinkable and * purgeable counts. @@ -440,6 +443,7 @@ static void xe_ttm_tt_account_add(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm); + update_global_total_pages(&xe->ttm, tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, tt-
num_pages);
else @@ -450,6 +454,7 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm); + update_global_total_pages(&xe->ttm, -(long)tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, -(long)tt-
num_pages);
else @@ -575,7 +580,6 @@ static int xe_ttm_tt_populate(struct ttm_device *ttm_dev, struct ttm_tt *tt, xe_tt->purgeable = false; xe_ttm_tt_account_add(ttm_to_xe_device(ttm_dev), tt); - update_global_total_pages(ttm_dev, tt->num_pages); return 0; } @@ -592,7 +596,6 @@ static void xe_ttm_tt_unpopulate(struct ttm_device *ttm_dev, struct ttm_tt *tt) ttm_pool_free(&ttm_dev->pool, tt); xe_ttm_tt_account_subtract(xe, tt); - update_global_total_pages(ttm_dev, -(long)tt->num_pages); } static void xe_ttm_tt_destroy(struct ttm_device *ttm_dev, struct ttm_tt *tt)
On Wed, Jan 07, 2026 at 01:01:12PM -0700, Summers, Stuart wrote:
On Tue, 2026-01-06 at 16:21 -0800, Matthew Brost wrote:
Page accounting can change via the shrinker without calling xe_ttm_tt_unpopulate(), but those paths already update accounting through the xe_ttm_tt_account_*() helpers.
I see this is getting also called through the xe_bo_pin/unpin functions with a check for ttm_tt_is_populated(). Does that mean after this change we'd get a double accounting in those cases?
Ah, good catch. It would actually be the inverse of that - we'd not account for pinned pages in global page counter. Let me fix this.
Matt
Thanks, Stuart
Move the page count tracepoints into xe_ttm_tt_account_add() and xe_ttm_tt_account_subtract() so accounting updates are recorded consistently, regardless of whether pages are populated, unpopulated, or reclaimed via the shrinker.
This avoids missing page count updates and keeps global accounting balanced across all TT lifecycle paths.
Cc: stable@vger.kernel.org Fixes: ce3d39fae3d3 ("drm/xe/bo: add GPU memory trace points") Signed-off-by: Matthew Brost matthew.brost@intel.com
drivers/gpu/drm/xe/xe_bo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 8b6474cd3eaf..33afaee38f48 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -432,6 +432,9 @@ struct sg_table *xe_bo_sg(struct xe_bo *bo) return xe_tt->sg; } +static void update_global_total_pages(struct ttm_device *ttm_dev, + long num_pages);
/* * Account ttm pages against the device shrinker's shrinkable and * purgeable counts. @@ -440,6 +443,7 @@ static void xe_ttm_tt_account_add(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm); + update_global_total_pages(&xe->ttm, tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, tt-
num_pages);
else @@ -450,6 +454,7 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt) { struct xe_ttm_tt *xe_tt = container_of(tt, struct xe_ttm_tt, ttm); + update_global_total_pages(&xe->ttm, -(long)tt->num_pages); if (xe_tt->purgeable) xe_shrinker_mod_pages(xe->mem.shrinker, 0, -(long)tt-
num_pages);
else @@ -575,7 +580,6 @@ static int xe_ttm_tt_populate(struct ttm_device *ttm_dev, struct ttm_tt *tt, xe_tt->purgeable = false; xe_ttm_tt_account_add(ttm_to_xe_device(ttm_dev), tt); - update_global_total_pages(ttm_dev, tt->num_pages); return 0; } @@ -592,7 +596,6 @@ static void xe_ttm_tt_unpopulate(struct ttm_device *ttm_dev, struct ttm_tt *tt) ttm_pool_free(&ttm_dev->pool, tt); xe_ttm_tt_account_subtract(xe, tt); - update_global_total_pages(ttm_dev, -(long)tt->num_pages); } static void xe_ttm_tt_destroy(struct ttm_device *ttm_dev, struct ttm_tt *tt)
linux-stable-mirror@lists.linaro.org