diff options
Diffstat (limited to 'drivers/gpu/drm/xe/xe_shrinker.c')
| -rw-r--r-- | drivers/gpu/drm/xe/xe_shrinker.c | 51 | 
1 files changed, 47 insertions, 4 deletions
| diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c index 1c3c04d52f55..90244fe59b59 100644 --- a/drivers/gpu/drm/xe/xe_shrinker.c +++ b/drivers/gpu/drm/xe/xe_shrinker.c @@ -54,10 +54,10 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea  	write_unlock(&shrinker->lock);  } -static s64 xe_shrinker_walk(struct xe_device *xe, -			    struct ttm_operation_ctx *ctx, -			    const struct xe_bo_shrink_flags flags, -			    unsigned long to_scan, unsigned long *scanned) +static s64 __xe_shrinker_walk(struct xe_device *xe, +			      struct ttm_operation_ctx *ctx, +			      const struct xe_bo_shrink_flags flags, +			      unsigned long to_scan, unsigned long *scanned)  {  	unsigned int mem_type;  	s64 freed = 0, lret; @@ -93,6 +93,48 @@ static s64 xe_shrinker_walk(struct xe_device *xe,  	return freed;  } +/* + * Try shrinking idle objects without writeback first, then if not sufficient, + * try also non-idle objects and finally if that's not sufficient either, + * add writeback. This avoids stalls and explicit writebacks with light or + * moderate memory pressure. + */ +static s64 xe_shrinker_walk(struct xe_device *xe, +			    struct ttm_operation_ctx *ctx, +			    const struct xe_bo_shrink_flags flags, +			    unsigned long to_scan, unsigned long *scanned) +{ +	bool no_wait_gpu = true; +	struct xe_bo_shrink_flags save_flags = flags; +	s64 lret, freed; + +	swap(no_wait_gpu, ctx->no_wait_gpu); +	save_flags.writeback = false; +	lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned); +	swap(no_wait_gpu, ctx->no_wait_gpu); +	if (lret < 0 || *scanned >= to_scan) +		return lret; + +	freed = lret; +	if (!ctx->no_wait_gpu) { +		lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned); +		if (lret < 0) +			return lret; +		freed += lret; +		if (*scanned >= to_scan) +			return freed; +	} + +	if (flags.writeback) { +		lret = __xe_shrinker_walk(xe, ctx, flags, to_scan, scanned); +		if (lret < 0) +			return lret; +		freed += lret; +	} + +	return freed; +} +  static unsigned long  xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)  { @@ -199,6 +241,7 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con  		runtime_pm = xe_shrinker_runtime_pm_get(shrinker, true, 0, can_backup);  	shrink_flags.purge = false; +  	lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,  				nr_to_scan, &nr_scanned);  	if (lret >= 0) | 
