[Intel-xe] [PATCH V8 6/6] drm/xe: Add min/max cap for engine scheduler properties

Matthew Brost matthew.brost at intel.com
Wed Jul 26 17:00:33 UTC 2023


On Wed, Jul 26, 2023 at 09:10:52AM -0600, Upadhyay, Tejas wrote:
> 
> 
> > -----Original Message-----
> > From: Brost, Matthew <matthew.brost at intel.com>
> > Sent: Wednesday, July 26, 2023 7:48 PM
> > To: Upadhyay, Tejas <tejas.upadhyay at intel.com>
> > Cc: intel-xe at lists.freedesktop.org; Vishwanathapura, Niranjana
> > <niranjana.vishwanathapura at intel.com>
> > Subject: Re: [PATCH V8 6/6] drm/xe: Add min/max cap for engine scheduler
> > properties
> > 
> > On Wed, Jul 26, 2023 at 06:55:50PM +0530, Tejas Upadhyay wrote:
> > > Add sysfs entries for the min, max, and defaults for each of engine
> > > scheduler controls for every hardware engine class.
> > >
> > > Non-elevated user IOCTLs to set these controls must be within the
> > > min-max ranges of the sysfs entries, elevated user can set these
> > > controls to any value. However, introduced compile time CONFIG min-max
> > > values which restricts elevated user to be in compile time min-max
> > > range if at all sysfs min/max are violated.
> > >
> > > Sysfs entries examples are,
> > > DUT# cat /sys/class/drm/cardX/device/tileN/gtN/engines/ccs/.defaults/
> > > job_timeout_max         job_timeout_ms          preempt_timeout_min
> > timeslice_duration_max  timeslice_duration_us
> > > job_timeout_min         preempt_timeout_max     preempt_timeout_us
> > timeslice_duration_min
> > >
> > > DUT# cat /sys/class/drm/card1/device/tileN/gtN/engines/ccs/
> > > .defaults/              job_timeout_min         preempt_timeout_max
> > preempt_timeout_us      timeslice_duration_min
> > > job_timeout_max         job_timeout_ms          preempt_timeout_min
> > timeslice_duration_max  timeslice_duration_us
> > >
> > > V8 :
> > >    - fix enforce_sched_limit and avoid code duplication - Niranjana
> > >    - Make sure min < max - Niranjana
> > > V7 :
> > >    - Rebase to replace hw engine with eclass interface
> > >    - return EINVAL in place of EPERM
> > >    - Use some APIs to avoid code duplication
> > > V6 :
> > >    - Rebase changes to reflect per engine class props interface - MattB
> > >    - Use #if ENABLED - MattB
> > >    - Remove MAX_SCHED_TIMEOUT check as range validation is enough
> > > V5 :
> > >    - Rebase to resolve conflicts - CI
> > > V4 :
> > >    - Rebase
> > >    - Update commit to reflect tile addition
> > >    - Use XE_HW macro directly as they are already filtered
> > >      for CONFIG checks - Niranjana
> > >    - Add CONFIG for enable/disable min/max limitation
> > >      on elevated user. Default is enable - Matt/Joonas
> > > V3 :
> > >    - Resolve CI hooks warning for kernel-doc
> > > V2 :
> > >    - Restric min/max setting to #define default min/max for
> > >      elevated user - Himal
> > >    - Remove unrelated changes from patch - Niranjana
> > >
> > > Signed-off-by: Tejas Upadhyay <tejas.upadhyay at intel.com>
> > > ---
> > >  drivers/gpu/drm/xe/Kconfig                 |   6 +
> > >  drivers/gpu/drm/xe/Kconfig.profile         |  46 +++
> > >  drivers/gpu/drm/xe/xe_engine.c             |  40 ++-
> > >  drivers/gpu/drm/xe/xe_engine_class_sysfs.c | 354
> > +++++++++++++++++++++
> > >  drivers/gpu/drm/xe/xe_engine_class_sysfs.h |   2 +
> > >  drivers/gpu/drm/xe/xe_hw_engine.c          |   8 +
> > >  drivers/gpu/drm/xe/xe_hw_engine.h          |  31 ++
> > >  7 files changed, 481 insertions(+), 6 deletions(-)  create mode
> > > 100644 drivers/gpu/drm/xe/Kconfig.profile
> > >
> > > diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
> > > index d44794f99338..0a4ea965645b 100644
> > > --- a/drivers/gpu/drm/xe/Kconfig
> > > +++ b/drivers/gpu/drm/xe/Kconfig
> > > @@ -83,3 +83,9 @@ depends on DRM_XE
> > >  depends on EXPERT
> > >  source "drivers/gpu/drm/xe/Kconfig.debug"
> > >  endmenu
> > > +
> > > +menu "drm/xe Profile Guided Optimisation"
> > > +	visible if EXPERT
> > > +	depends on DRM_XE
> > > +	source "drivers/gpu/drm/xe/Kconfig.profile"
> > > +endmenu
> > > diff --git a/drivers/gpu/drm/xe/Kconfig.profile
> > > b/drivers/gpu/drm/xe/Kconfig.profile
> > > new file mode 100644
> > > index 000000000000..e72f15ec4bf6
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/Kconfig.profile
> > > @@ -0,0 +1,46 @@
> > > +config DRM_XE_JOB_TIMEOUT_MAX
> > > +       int "Default max job timeout (ms)"
> > > +       default 10000 # milliseconds
> > > +       help
> > > +         Configures the default max job timeout after which job will
> > > +         be forcefully taken away from scheduler.
> > > +config DRM_XE_JOB_TIMEOUT_MIN
> > > +       int "Default max job timeout (ms)"
> > > +       default 1 # milliseconds
> > > +       help
> > > +         Configures the default min job timeout after which job will
> > > +         be forcefully taken away from scheduler.
> > > +config DRM_XE_TIMESLICE_MAX
> > > +       int "Default max timeslice duration (us)"
> > > +       default 10000000 # microseconds
> > > +       help
> > > +         Configures the default max timeslice duration between multiple
> > > +         contexts by guc scheduling.
> > > +config DRM_XE_TIMESLICE_MIN
> > > +       int "Default min timeslice duration (us)"
> > > +       default 1 # microseconds
> > > +       help
> > > +         Configures the default min timeslice duration between multiple
> > > +         contexts by guc scheduling.
> > > +config DRM_XE_PREEMPT_TIMEOUT_MAX
> > > +       int "Default max  preempt timeout (us)"
> > > +       default 10000000 # microseconds
> > > +       help
> > > +         Configures the default max preempt timeout after which context
> > > +         will be forcefully taken away and higher priority context will
> > > +         run.
> > > +config DRM_XE_PREEMPT_TIMEOUT_MIN
> > > +       int "Default min  preempt timeout (us)"
> > > +       default 1 # microseconds
> > > +       help
> > > +         Configures the default min preempt timeout after which context
> > > +         will be forcefully taken away and higher priority context will
> > > +         run.
> > > +config DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT
> > > +       bool "Default configuration of limitation on scheduler timeout"
> > > +       default y
> > > +       help
> > > +	 Configures the enablement of limitation on scheduler timeout
> > > +	 to apply to applicable user. For elevated user, all above MIN
> > > +	 and MAX values will apply when this configuration is enable to
> > > +	 apply limitation. By default limitation is applied.
> > > diff --git a/drivers/gpu/drm/xe/xe_engine.c
> > > b/drivers/gpu/drm/xe/xe_engine.c index 9e167b113963..a558918f9a64
> > > 100644
> > > --- a/drivers/gpu/drm/xe/xe_engine.c
> > > +++ b/drivers/gpu/drm/xe/xe_engine.c
> > > @@ -12,6 +12,7 @@
> > >  #include <drm/xe_drm.h>
> > >
> > >  #include "xe_device.h"
> > > +#include "xe_engine_class_sysfs.h"
> > >  #include "xe_gt.h"
> > >  #include "xe_hw_fence.h"
> > >  #include "xe_lrc.h"
> > > @@ -191,8 +192,17 @@ static int engine_set_priority(struct xe_device
> > > *xe, struct xe_engine *e,  static int engine_set_timeslice(struct xe_device
> > *xe, struct xe_engine *e,
> > >  				u64 value, bool create)
> > >  {
> > > -	if (!capable(CAP_SYS_NICE))
> > > -		return -EPERM;
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_TIMESLICE_MIN;
> > > +	u32 max = XE_HW_ENGINE_TIMESLICE_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.timeslice_min;
> > > +	u32 max = e->hwe->eclass->sched_props.timeslice_max;
> > > +#endif
> > 
> > The min / max here should just be e->hwe->eclass->sched_props, right? We
> > enforce that the user cannot change these values via sysfs to an illegal value.
> 
> We also enforce elevated user to not violate compile configs min/max when CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT is enabled.
> 

But still this doesn't make any sense to have this in two places, the
sysfs is the only place where we need to check this.

As you have it coded if CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT is
enabled then the min / max sysfs entries are basically unused. We want
the sysfs entries to be bounds and the user can only set the sysfs
entries to within the Kconfig allowed range. We know the sysfs entries
are within the bounds, thus we only check the sysfs entries. It also
allows the user to do something like this.

KCONFIG_MIN=5
KCONFIG_MAX=10

user set sysfs MIN=2	# rejected by the kernel
user set via IOCTL=6	# Allowed
user set sysfs MIN=8	# Allowed
user set via IOCTL=6	# Rejected

Following this logic you only need to enforce
CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT when setting the min / max sysfs
entries, everywhere else just use e->hwe->eclass->sched_props for the
bounds checks.

Matt

> Thanks,
> Tejas
> > 
> > Matt
> > 
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(value, min, max))
> > > +		return -EINVAL;
> > >
> > >  	return e->ops->set_timeslice(e, value);  } @@ -201,8 +211,17 @@
> > > static int engine_set_preemption_timeout(struct xe_device *xe,
> > >  					 struct xe_engine *e, u64 value,
> > >  					 bool create)
> > >  {
> > > -	if (!capable(CAP_SYS_NICE))
> > > -		return -EPERM;
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN;
> > > +	u32 max = XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.preempt_timeout_min;
> > > +	u32 max = e->hwe->eclass->sched_props.preempt_timeout_max;
> > > +#endif
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(value, min, max))
> > > +		return -EINVAL;
> > >
> > >  	return e->ops->set_preempt_timeout(e, value);  } @@ -266,11
> > +285,20
> > > @@ static int engine_set_persistence(struct xe_device *xe, struct
> > > xe_engine *e,  static int engine_set_job_timeout(struct xe_device *xe,
> > struct xe_engine *e,
> > >  				  u64 value, bool create)
> > >  {
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_JOB_TIMEOUT_MIN;
> > > +	u32 max = XE_HW_ENGINE_JOB_TIMEOUT_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.job_timeout_min;
> > > +	u32 max = e->hwe->eclass->sched_props.job_timeout_max;
> > > +#endif
> > > +
> > >  	if (XE_IOCTL_DBG(xe, !create))
> > >  		return -EINVAL;
> > >
> > > -	if (!capable(CAP_SYS_NICE))
> > > -		return -EPERM;
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(value, min, max))
> > > +		return -EINVAL;
> > >
> > >  	return e->ops->set_job_timeout(e, value);  } diff --git
> > > a/drivers/gpu/drm/xe/xe_engine_class_sysfs.c
> > > b/drivers/gpu/drm/xe/xe_engine_class_sysfs.c
> > > index 569d5f89310e..4a749e91de5d 100644
> > > --- a/drivers/gpu/drm/xe/xe_engine_class_sysfs.c
> > > +++ b/drivers/gpu/drm/xe/xe_engine_class_sysfs.c
> > > @@ -11,6 +11,20 @@
> > >
> > >  static int xe_add_engine_class_defaults(struct kobject *parent);
> > >
> > > +bool enforce_schedule_limit(void)
> > > +{
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	return true;
> > > +#else
> > > +	return !capable(CAP_SYS_NICE);
> > > +#endif
> > > +}
> > > +
> > > +bool engine_timeout_in_range(u64 timeout, u64 min, u64 max) {
> > > +	return timeout >= min && timeout <= max; }
> > > +
> > >  static void kobj_xe_engine_release(struct kobject *kobj)  {
> > >  	kfree(kobj);
> > > @@ -39,11 +53,92 @@ kobj_xe_engine(struct kobject *parent, char
> > *name)
> > >  	return keclass;
> > >  }
> > >
> > > +static ssize_t job_timeout_max_store(struct kobject *kobj,
> > > +				     struct kobj_attribute *attr,
> > > +				     const char *buf, size_t count) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 timeout;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &timeout);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (timeout < eclass->sched_props.job_timeout_min)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout,
> > > +				     XE_HW_ENGINE_JOB_TIMEOUT_MIN,
> > > +				     XE_HW_ENGINE_JOB_TIMEOUT_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.job_timeout_max, timeout);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t job_timeout_max_show(struct kobject *kobj,
> > > +				    struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->sched_props.job_timeout_max);
> > > +}
> > > +
> > > +static struct kobj_attribute job_timeout_max_attr =
> > > +__ATTR(job_timeout_max, 0644, job_timeout_max_show,
> > > +job_timeout_max_store);
> > > +
> > > +static ssize_t job_timeout_min_store(struct kobject *kobj,
> > > +				     struct kobj_attribute *attr,
> > > +				     const char *buf, size_t count) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 timeout;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &timeout);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (timeout > eclass->sched_props.job_timeout_max)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout,
> > > +				     XE_HW_ENGINE_JOB_TIMEOUT_MIN,
> > > +				     XE_HW_ENGINE_JOB_TIMEOUT_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.job_timeout_min, timeout);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t job_timeout_min_show(struct kobject *kobj,
> > > +				    struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->sched_props.job_timeout_min);
> > > +}
> > > +
> > > +static struct kobj_attribute job_timeout_min_attr =
> > > +__ATTR(job_timeout_min, 0644, job_timeout_min_show,
> > > +job_timeout_min_store);
> > > +
> > >  static ssize_t job_timeout_store(struct kobject *kobj,
> > >  				 struct kobj_attribute *attr,
> > >  				 const char *buf, size_t count)
> > >  {
> > >  	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_JOB_TIMEOUT_MIN;
> > > +	u32 max = XE_HW_ENGINE_JOB_TIMEOUT_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.job_timeout_min;
> > > +	u32 max = e->hwe->eclass->sched_props.job_timeout_max;
> > > +#endif
> > >  	u32 timeout;
> > >  	int err;
> > >
> > > @@ -51,6 +146,10 @@ static ssize_t job_timeout_store(struct kobject
> > *kobj,
> > >  	if (err)
> > >  		return err;
> > >
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout, min, max))
> > > +		return -EINVAL;
> > > +
> > >  	WRITE_ONCE(eclass->sched_props.job_timeout_ms, timeout);
> > >
> > >  	return count;
> > > @@ -78,11 +177,40 @@ static ssize_t job_timeout_default(struct kobject
> > > *kobj,  static struct kobj_attribute job_timeout_def =
> > > __ATTR(job_timeout_ms, 0444, job_timeout_default, NULL);
> > >
> > > +static ssize_t job_timeout_min_default(struct kobject *kobj,
> > > +				       struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.job_timeout_min);
> > > +}
> > > +
> > > +static struct kobj_attribute job_timeout_min_def =
> > > +__ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL);
> > > +
> > > +static ssize_t job_timeout_max_default(struct kobject *kobj,
> > > +				       struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.job_timeout_max);
> > > +}
> > > +
> > > +static struct kobj_attribute job_timeout_max_def =
> > > +__ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL);
> > > +
> > >  static ssize_t timeslice_duration_store(struct kobject *kobj,
> > >  					struct kobj_attribute *attr,
> > >  					const char *buf, size_t count)
> > >  {
> > >  	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_TIMESLICE_MIN;
> > > +	u32 max = XE_HW_ENGINE_TIMESLICE_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.timeslice_min;
> > > +	u32 max = e->hwe->eclass->sched_props.timeslice_max;
> > > +#endif
> > >  	u32 duration;
> > >  	int err;
> > >
> > > @@ -90,11 +218,92 @@ static ssize_t timeslice_duration_store(struct
> > kobject *kobj,
> > >  	if (err)
> > >  		return err;
> > >
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(duration, min, max))
> > > +		return -EINVAL;
> > > +
> > >  	WRITE_ONCE(eclass->sched_props.timeslice_us, duration);
> > >
> > >  	return count;
> > >  }
> > >
> > > +static ssize_t timeslice_duration_max_store(struct kobject *kobj,
> > > +					    struct kobj_attribute *attr,
> > > +					    const char *buf, size_t count) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 duration;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &duration);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (duration < eclass->sched_props.timeslice_min)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(duration,
> > > +				     XE_HW_ENGINE_TIMESLICE_MIN,
> > > +				     XE_HW_ENGINE_TIMESLICE_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.timeslice_max, duration);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t timeslice_duration_max_show(struct kobject *kobj,
> > > +		struct kobj_attribute *attr,
> > > +		char *buf)
> > > +{
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->sched_props.timeslice_max);
> > > +}
> > > +
> > > +static struct kobj_attribute timeslice_duration_max_attr =
> > > +	__ATTR(timeslice_duration_max, 0644,
> > timeslice_duration_max_show,
> > > +	       timeslice_duration_max_store);
> > > +
> > > +static ssize_t timeslice_duration_min_store(struct kobject *kobj,
> > > +					    struct kobj_attribute *attr,
> > > +					    const char *buf, size_t count) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 duration;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &duration);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (duration > eclass->sched_props.timeslice_max)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(duration,
> > > +				     XE_HW_ENGINE_TIMESLICE_MIN,
> > > +				     XE_HW_ENGINE_TIMESLICE_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.timeslice_min, duration);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t timeslice_duration_min_show(struct kobject *kobj,
> > > +					   struct kobj_attribute *attr, char
> > *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->sched_props.timeslice_min);
> > > +}
> > > +
> > > +static struct kobj_attribute timeslice_duration_min_attr =
> > > +	__ATTR(timeslice_duration_min, 0644,
> > timeslice_duration_min_show,
> > > +	       timeslice_duration_min_store);
> > > +
> > >  static ssize_t timeslice_duration_show(struct kobject *kobj,
> > >  		struct kobj_attribute *attr, char *buf)  { @@ -118,11 +327,40
> > @@
> > > static ssize_t timeslice_default(struct kobject *kobj,  static struct
> > > kobj_attribute timeslice_duration_def =  __ATTR(timeslice_duration_us,
> > > 0444, timeslice_default, NULL);
> > >
> > > +static ssize_t timeslice_min_default(struct kobject *kobj,
> > > +				     struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.timeslice_min); }
> > > +
> > > +static struct kobj_attribute timeslice_duration_min_def =
> > > +__ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL);
> > > +
> > > +static ssize_t timeslice_max_default(struct kobject *kobj,
> > > +				     struct kobj_attribute *attr, char *buf) {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.timeslice_max); }
> > > +
> > > +static struct kobj_attribute timeslice_duration_max_def =
> > > +__ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL);
> > > +
> > >  static ssize_t preempt_timeout_store(struct kobject *kobj,
> > >  				     struct kobj_attribute *attr,
> > >  				     const char *buf, size_t count)  {
> > >  	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +#if IS_ENABLED(CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT)
> > > +	u32 min = XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN;
> > > +	u32 max = XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX; #else
> > > +	u32 min = e->hwe->eclass->sched_props.preempt_timeout_min;
> > > +	u32 max = e->hwe->eclass->sched_props.preempt_timeout_max;
> > > +#endif
> > >  	u32 timeout;
> > >  	int err;
> > >
> > > @@ -130,6 +368,10 @@ static ssize_t preempt_timeout_store(struct
> > kobject *kobj,
> > >  	if (err)
> > >  		return err;
> > >
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout, min, max))
> > > +		return -EINVAL;
> > > +
> > >  	WRITE_ONCE(eclass->sched_props.preempt_timeout_us, timeout);
> > >
> > >  	return count;
> > > @@ -158,17 +400,129 @@ static ssize_t preempt_timeout_default(struct
> > > kobject *kobj,  static struct kobj_attribute preempt_timeout_def =
> > > __ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL);
> > >
> > > +static ssize_t preempt_timeout_min_default(struct kobject *kobj,
> > > +					   struct kobj_attribute *attr,
> > > +					   char *buf)
> > > +{
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.preempt_timeout_min);
> > > +}
> > > +
> > > +static struct kobj_attribute preempt_timeout_min_def =
> > > +__ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default,
> > NULL);
> > > +
> > > +static ssize_t preempt_timeout_max_default(struct kobject *kobj,
> > > +					   struct kobj_attribute *attr,
> > > +					   char *buf)
> > > +{
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
> > > +
> > > +	return sprintf(buf, "%u\n", eclass->defaults.preempt_timeout_max);
> > > +}
> > > +
> > > +static struct kobj_attribute preempt_timeout_max_def =
> > > +__ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default,
> > NULL);
> > > +
> > > +static ssize_t preempt_timeout_max_store(struct kobject *kobj,
> > > +					 struct kobj_attribute *attr,
> > > +					 const char *buf, size_t count)
> > > +{
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 timeout;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &timeout);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (timeout < eclass->sched_props.preempt_timeout_min)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout,
> > > +
> > XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
> > > +
> > XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.preempt_timeout_max, timeout);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t preempt_timeout_max_show(struct kobject *kobj,
> > > +					struct kobj_attribute *attr, char *buf)
> > {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n",
> > > +eclass->sched_props.preempt_timeout_max);
> > > +}
> > > +
> > > +static struct kobj_attribute preempt_timeout_max_attr =
> > > +	__ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show,
> > > +	       preempt_timeout_max_store);
> > > +
> > > +static ssize_t preempt_timeout_min_store(struct kobject *kobj,
> > > +					 struct kobj_attribute *attr,
> > > +					 const char *buf, size_t count)
> > > +{
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +	u32 timeout;
> > > +	int err;
> > > +
> > > +	err = kstrtou32(buf, 0, &timeout);
> > > +	if (err)
> > > +		return err;
> > > +
> > > +	if (timeout > eclass->sched_props.preempt_timeout_max)
> > > +		return -EINVAL;
> > > +
> > > +	if (enforce_schedule_limit() &&
> > > +	    !engine_timeout_in_range(timeout,
> > > +
> > XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
> > > +
> > XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
> > > +		return -EINVAL;
> > > +
> > > +	WRITE_ONCE(eclass->sched_props.preempt_timeout_min, timeout);
> > > +
> > > +	return count;
> > > +}
> > > +
> > > +static ssize_t preempt_timeout_min_show(struct kobject *kobj,
> > > +					struct kobj_attribute *attr, char *buf)
> > {
> > > +	struct xe_engine_class_intf *eclass = kobj_to_eclass(kobj);
> > > +
> > > +	return sprintf(buf, "%u\n",
> > > +eclass->sched_props.preempt_timeout_min);
> > > +}
> > > +
> > > +static struct kobj_attribute preempt_timeout_min_attr =
> > > +	__ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show,
> > > +	       preempt_timeout_min_store);
> > > +
> > >  static const struct attribute *defaults[] = {
> > >  	&job_timeout_def.attr,
> > > +	&job_timeout_min_def.attr,
> > > +	&job_timeout_max_def.attr,
> > >  	&timeslice_duration_def.attr,
> > > +	&timeslice_duration_min_def.attr,
> > > +	&timeslice_duration_max_def.attr,
> > >  	&preempt_timeout_def.attr,
> > > +	&preempt_timeout_min_def.attr,
> > > +	&preempt_timeout_max_def.attr,
> > >  	NULL
> > >  };
> > >
> > >  static const struct attribute *files[] = {
> > >  	&job_timeout_attr.attr,
> > > +	&job_timeout_min_attr.attr,
> > > +	&job_timeout_max_attr.attr,
> > >  	&timeslice_duration_attr.attr,
> > > +	&timeslice_duration_min_attr.attr,
> > > +	&timeslice_duration_max_attr.attr,
> > >  	&preempt_timeout_attr.attr,
> > > +	&preempt_timeout_min_attr.attr,
> > > +	&preempt_timeout_max_attr.attr,
> > >  	NULL
> > >  };
> > >
> > > diff --git a/drivers/gpu/drm/xe/xe_engine_class_sysfs.h
> > > b/drivers/gpu/drm/xe/xe_engine_class_sysfs.h
> > > index 683726563059..33c458606117 100644
> > > --- a/drivers/gpu/drm/xe/xe_engine_class_sysfs.h
> > > +++ b/drivers/gpu/drm/xe/xe_engine_class_sysfs.h
> > > @@ -10,6 +10,8 @@
> > >
> > >  #define MAX_ENGINE_CLASS_NAME_LEN    16
> > >  int xe_engine_class_sysfs_init(struct xe_gt *gt);
> > > +bool enforce_schedule_limit(void);
> > > +bool engine_timeout_in_range(u64 timeout, u64 min, u64 max);
> > >
> > >  /**
> > >   * struct kobj_eclass - A eclass's kobject struct that connects the
> > > kobject and the diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c
> > > b/drivers/gpu/drm/xe/xe_hw_engine.c
> > > index 96c32a815c90..06a98ea9800b 100644
> > > --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> > > +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> > > @@ -364,8 +364,16 @@ static void hw_engine_init_early(struct xe_gt
> > > *gt, struct xe_hw_engine *hwe,
> > >
> > >  	if (!gt->eclass[hwe->class].init_done) {
> > >  		gt->eclass[hwe->class].sched_props.job_timeout_ms = HZ *
> > 5;
> > > +		gt->eclass[hwe->class].sched_props.job_timeout_min =
> > XE_HW_ENGINE_JOB_TIMEOUT_MIN;
> > > +		gt->eclass[hwe->class].sched_props.job_timeout_max =
> > > +XE_HW_ENGINE_JOB_TIMEOUT_MAX;
> > >  		gt->eclass[hwe->class].sched_props.timeslice_us = 1 * 1000;
> > > +		gt->eclass[hwe->class].sched_props.timeslice_min =
> > XE_HW_ENGINE_TIMESLICE_MIN;
> > > +		gt->eclass[hwe->class].sched_props.timeslice_max =
> > > +XE_HW_ENGINE_TIMESLICE_MAX;
> > >  		gt->eclass[hwe->class].sched_props.preempt_timeout_us =
> > 640 * 1000;
> > > +		gt->eclass[hwe->class].sched_props.preempt_timeout_min =
> > > +
> > 	XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN;
> > > +		gt->eclass[hwe->class].sched_props.preempt_timeout_max =
> > > +
> > 	XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX;
> > >  		/* Record default props */
> > >  		gt->eclass[hwe->class].defaults = gt->eclass[hwe-
> > >class].sched_props;
> > >  		gt->eclass[hwe->class].init_done = true; diff --git
> > > a/drivers/gpu/drm/xe/xe_hw_engine.h
> > > b/drivers/gpu/drm/xe/xe_hw_engine.h
> > > index 7eca9d53c7b1..3d37d6d44261 100644
> > > --- a/drivers/gpu/drm/xe/xe_hw_engine.h
> > > +++ b/drivers/gpu/drm/xe/xe_hw_engine.h
> > > @@ -10,6 +10,37 @@
> > >
> > >  struct drm_printer;
> > >
> > > +#ifdef CONFIG_DRM_XE_JOB_TIMEOUT_MIN
> > > +#define XE_HW_ENGINE_JOB_TIMEOUT_MIN
> > CONFIG_DRM_XE_JOB_TIMEOUT_MIN
> > > +#else #define XE_HW_ENGINE_JOB_TIMEOUT_MIN 1 #endif #ifdef
> > > +CONFIG_DRM_XE_JOB_TIMEOUT_MAX #define
> > XE_HW_ENGINE_JOB_TIMEOUT_MAX
> > > +CONFIG_DRM_XE_JOB_TIMEOUT_MAX #else #define
> > > +XE_HW_ENGINE_JOB_TIMEOUT_MAX (10 * 1000) #endif #ifdef
> > > +CONFIG_DRM_XE_TIMESLICE_MIN #define
> > XE_HW_ENGINE_TIMESLICE_MIN
> > > +CONFIG_DRM_XE_TIMESLICE_MIN #else #define
> > XE_HW_ENGINE_TIMESLICE_MIN
> > > +1 #endif #ifdef CONFIG_DRM_XE_TIMESLICE_MAX #define
> > > +XE_HW_ENGINE_TIMESLICE_MAX CONFIG_DRM_XE_TIMESLICE_MAX
> > #else #define
> > > +XE_HW_ENGINE_TIMESLICE_MAX (10 * 1000 * 1000) #endif #ifdef
> > > +CONFIG_DRM_XE_PREEMPT_TIMEOUT_MIN
> > > +#define XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN
> > > +CONFIG_DRM_XE_PREEMPT_TIMEOUT_MIN #else #define
> > > +XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN 1 #endif #ifdef
> > > +CONFIG_DRM_XE_PREEMPT_TIMEOUT_MAX
> > > +#define XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX
> > > +CONFIG_DRM_XE_PREEMPT_TIMEOUT_MAX #else #define
> > > +XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX (10 * 1000 * 1000) #endif
> > > +
> > >  int xe_hw_engines_init_early(struct xe_gt *gt);  int
> > > xe_hw_engines_init(struct xe_gt *gt);  void
> > > xe_hw_engine_handle_irq(struct xe_hw_engine *hwe, u16 intr_vec);
> > > --
> > > 2.25.1
> > >


More information about the Intel-xe mailing list