[PATCH 67/67] ctx-freq

Chris Wilson chris at chris-wilson.co.uk
Thu Jan 11 12:37:42 UTC 2018


---
 drivers/gpu/drm/i915/i915_drv.h             |  2 +
 drivers/gpu/drm/i915/i915_gem_context.c     | 67 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem_context.h     |  3 ++
 drivers/gpu/drm/i915/i915_irq.c             | 55 +++++++++++------------
 drivers/gpu/drm/i915/intel_gt_pm.c          |  3 ++
 drivers/gpu/drm/i915/intel_guc_submission.c | 24 +++++++++++
 drivers/gpu/drm/i915/intel_lrc.c            | 24 +++++++++++
 include/uapi/drm/i915_drm.h                 |  9 ++++
 8 files changed, 160 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d169b74cc35a..524d61932f94 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -918,6 +918,8 @@ struct intel_rps {
 	u8 cur_freq;		/* Current frequency (cached, may not == HW) */
 	u8 min_freq_softlimit;	/* Minimum frequency permitted by the driver */
 	u8 max_freq_softlimit;	/* Max frequency permitted by the driver */
+	u8 min_freq_context;	/* Minimum frequency permitted by the driver */
+	u8 max_freq_context;	/* Max frequency permitted by the driver */
 	u8 max_freq;		/* Maximum frequency, RP0 if not overclocking */
 	u8 min_freq;		/* AKA RPn. Minimum frequency */
 	u8 boost_freq;		/* Frequency to request when wait boosting */
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index cd4e41a72dd7..ab5848f56e38 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -88,8 +88,10 @@
 #include <linux/log2.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
+
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include "intel_gt_pm.h"
 
 #define ALL_L3_SLICES(dev) (1 << NUM_L3_SLICES(dev)) - 1
 
@@ -276,6 +278,8 @@ __create_hw_context(struct drm_i915_private *dev_priv,
 	list_add_tail(&ctx->link, &dev_priv->contexts.list);
 	ctx->i915 = dev_priv;
 	ctx->priority = I915_PRIORITY_NORMAL;
+	ctx->min_freq = dev_priv->gt_pm.rps.min_freq;
+	ctx->max_freq = dev_priv->gt_pm.rps.max_freq;
 
 	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
 	INIT_LIST_HEAD(&ctx->handles_list);
@@ -760,6 +764,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct drm_i915_gem_context_param *args = data;
+	struct drm_i915_private *i915 = to_i915(dev);
 	struct i915_gem_context *ctx;
 	int ret = 0;
 
@@ -792,6 +797,28 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 	case I915_CONTEXT_PARAM_PRIORITY:
 		args->value = ctx->priority >> I915_PRIORITY_SHIFT;
 		break;
+	case I915_CONTEXT_PARAM_FREQUENCY:
+		if (!HAS_RPS(i915) || !HAS_EXECLISTS(i915)) {
+			ret = -ENODEV;
+		} else if (args->size == 0) {
+		} else if (args->size < sizeof(struct drm_i915_gem_context_frequency)) {
+			ret = -EFAULT;
+		} else {
+			struct drm_i915_gem_context_frequency f = {
+				.min_frequency_mhz =
+					intel_gpu_freq(i915, ctx->min_freq),
+				.max_frequency_mhz =
+					intel_gpu_freq(i915, ctx->max_freq),
+			};
+			if (copy_to_user(u64_to_user_ptr(args->value),
+					 &f, sizeof(f))) {
+				ret = -EFAULT;
+			}
+		}
+		args->size =
+			sizeof(struct drm_i915_gem_context_frequency);
+		break;
+
 	default:
 		ret = -EINVAL;
 		break;
@@ -806,6 +833,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct drm_i915_gem_context_param *args = data;
+	struct drm_i915_private *i915 = to_i915(dev);
 	struct i915_gem_context *ctx;
 	int ret;
 
@@ -866,6 +894,45 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 				ctx->priority = priority << I915_PRIORITY_SHIFT;
 		}
 		break;
+	case I915_CONTEXT_PARAM_FREQUENCY:
+		{
+			struct drm_i915_gem_context_frequency f;
+
+			if (!HAS_RPS(i915) || !HAS_EXECLISTS(i915)) {
+				ret = -ENODEV;
+			} else if (args->size == 0) {
+			} else if (args->size < sizeof(f)) {
+				ret = -EFAULT;
+			} else if (copy_from_user(&f,
+						  u64_to_user_ptr(args->value),
+						  sizeof(f))) {
+				ret = -EFAULT;
+			} else {
+				struct intel_rps *rps = &i915->gt_pm.rps;
+				u32 min, max;
+
+				min = intel_freq_opcode(i915,
+							f.min_frequency_mhz);
+				max = intel_freq_opcode(i915,
+							f.max_frequency_mhz);
+				if (max < min) {
+					ret = -EINVAL;
+				} else if (min < rps->min_freq ||
+					   max > rps->max_freq) {
+					ret = -EINVAL;
+				} else if ((min > ctx->min_freq ||
+					    max > ctx->max_freq) &&
+					   !capable(CAP_SYS_NICE)) {
+					ret = -EPERM;
+				} else {
+					ctx->min_freq = min;
+					ctx->max_freq = max;
+				}
+			}
+
+			args->size = sizeof(f);
+			break;
+		}
 
 	default:
 		ret = -EINVAL;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
index cfa69b12a6b2..2f08153c192c 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
@@ -149,6 +149,9 @@ struct i915_gem_context {
 	 */
 	int priority;
 
+	u32 min_freq;
+	u32 max_freq;
+
 	/** ggtt_offset_bias: placement restriction for context objects */
 	u32 ggtt_offset_bias;
 
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 78294f9ee65a..3d573c950b59 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1179,33 +1179,32 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	struct drm_i915_private *dev_priv =
 		container_of(work, struct drm_i915_private, gt_pm.rps.work);
 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
-	bool client_boost = false;
-	int new_delay, adj, min, max;
-	u32 pm_iir;
+	u32 new_freq, min, max, pm_iir;
+	bool client_boost;
+	int adj;
 
 	pm_iir = 0;
 	if (rps->interrupts_enabled)
 		pm_iir = xchg(&rps->pm_iir, 0) & dev_priv->pm_rps_events;
 	if (IS_GEN5(dev_priv))
 		pm_iir = ilk_compute_pm_iir(dev_priv);
-	client_boost = READ_ONCE(rps->num_waiters);
+	pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
 
-	/* Make sure we didn't queue anything we're not going to process. */
-	if (!pm_iir && !client_boost)
-		goto out;
+	client_boost = READ_ONCE(rps->num_waiters);
 
 	mutex_lock(&rps->lock);
 
-	pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
-
-	adj = rps->last_adj;
-	new_delay = rps->cur_freq;
-	min = rps->min_freq_softlimit;
-	max = rps->max_freq_softlimit;
+	min = clamp(rps->min_freq_context,
+		    rps->min_freq_softlimit, rps->max_freq_softlimit);
+	max = clamp(rps->max_freq_context,
+		    rps->min_freq_softlimit, rps->max_freq_softlimit);
 	if (client_boost)
 		max = rps->max_freq;
-	if (client_boost && new_delay < rps->boost_freq) {
-		new_delay = rps->boost_freq;
+
+	adj = rps->last_adj;
+	new_freq = rps->cur_freq;
+	if (client_boost && new_freq < rps->boost_freq) {
+		new_freq = rps->boost_freq;
 		adj = 0;
 	} else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
 		if (adj > 0)
@@ -1213,44 +1212,46 @@ static void gen6_pm_rps_work(struct work_struct *work)
 		else /* CHV needs even encode values */
 			adj = IS_CHERRYVIEW(dev_priv) ? 2 : 1;
 
-		if (new_delay >= rps->max_freq_softlimit)
+		if (new_freq >= max)
 			adj = 0;
+
+		rps->last_adj = adj;
 	} else if (client_boost) {
 		adj = 0;
 	} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
 		if (rps->cur_freq > rps->efficient_freq)
-			new_delay = rps->efficient_freq;
-		else if (rps->cur_freq > rps->min_freq_softlimit)
-			new_delay = rps->min_freq_softlimit;
-		adj = 0;
+			new_freq = rps->efficient_freq;
+		else if (rps->cur_freq > min)
+			new_freq = min;
+
+		rps->last_adj = adj = 0;
 	} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
 		if (adj < 0)
 			adj *= 2;
 		else /* CHV needs even encode values */
 			adj = IS_CHERRYVIEW(dev_priv) ? -2 : -1;
 
-		if (new_delay <= rps->min_freq_softlimit)
+		if (new_freq <= min)
 			adj = 0;
+
+		rps->last_adj = adj;
 	} else { /* unknown event */
 		adj = 0;
 	}
 
-	rps->last_adj = adj;
-
 	/* sysfs frequency interfaces may have snuck in while servicing the
 	 * interrupt
 	 */
-	new_delay += adj;
-	new_delay = clamp_t(int, new_delay, min, max);
+	new_freq += adj;
+	new_freq = clamp(new_freq, min, max);
 
-	if (intel_set_rps(dev_priv, new_delay)) {
+	if (intel_set_rps(dev_priv, new_freq)) {
 		DRM_DEBUG_DRIVER("Failed to set new GPU frequency\n");
 		rps->last_adj = 0;
 	}
 
 	mutex_unlock(&rps->lock);
 
-out:
 	/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
 	spin_lock_irq(&dev_priv->irq_lock);
 	if (rps->interrupts_enabled)
diff --git a/drivers/gpu/drm/i915/intel_gt_pm.c b/drivers/gpu/drm/i915/intel_gt_pm.c
index f82ad32725a7..35fdd4676139 100644
--- a/drivers/gpu/drm/i915/intel_gt_pm.c
+++ b/drivers/gpu/drm/i915/intel_gt_pm.c
@@ -2207,6 +2207,9 @@ void intel_gt_pm_init(struct drm_i915_private *dev_priv)
 	rps->max_freq_softlimit = rps->max_freq;
 	rps->min_freq_softlimit = rps->min_freq;
 
+	rps->max_freq_context = rps->max_freq;
+	rps->min_freq_context = rps->min_freq;
+
 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 		rps->min_freq_softlimit =
 			max_t(int,
diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
index 528529c3abcf..6c457f5c2cec 100644
--- a/drivers/gpu/drm/i915/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
@@ -662,6 +662,29 @@ static void guc_submit(struct intel_engine_cs *engine)
 	}
 }
 
+static void update_gpufreq(struct intel_engine_cs *engine)
+{
+	struct intel_engine_execlists * const execlists = &engine->execlists;
+	struct i915_gem_context *ctx = port_request(execlists->port)->ctx;
+	struct intel_rps *rps = &engine->i915->gt_pm.rps;
+	u32 cur;
+
+	if (!HAS_RPS(engine->i915))
+		return;
+
+	rps->min_freq_context = ctx->min_freq;
+	rps->max_freq_context = ctx->max_freq;
+
+	/*
+	 * If we are running below the request frequested, kick the worker to
+	 * jump to the new frequency. Otherwise, we let the frequency decay
+	 * naturally.
+	 */
+	cur = READ_ONCE(rps->cur_freq);
+	if (cur < ctx->min_freq)
+		schedule_work(&rps->work);
+}
+
 static void port_assign(struct execlist_port *port,
 			struct drm_i915_gem_request *rq)
 {
@@ -742,6 +765,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
 		port_assign(port, last);
 		execlists_set_active(execlists, EXECLISTS_ACTIVE_USER);
 		guc_submit(engine);
+		update_gpufreq(engine);
 	}
 unlock:
 	spin_unlock_irq(&engine->timeline->lock);
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index a4adbfab1dee..744d07d6cbc4 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -509,6 +509,29 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 	execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK);
 }
 
+static void update_gpufreq(struct intel_engine_cs *engine)
+{
+	struct intel_engine_execlists * const execlists = &engine->execlists;
+	struct i915_gem_context *ctx = port_request(execlists->port)->ctx;
+	struct intel_rps *rps = &engine->i915->gt_pm.rps;
+	u32 cur;
+
+	if (!HAS_RPS(engine->i915))
+		return;
+
+	rps->min_freq_context = ctx->min_freq;
+	rps->max_freq_context = ctx->max_freq;
+
+	/*
+	 * If we are running below the request frequested, kick the worker to
+	 * jump to the new frequency. Otherwise, we let the frequency decay
+	 * naturally.
+	 */
+	cur = READ_ONCE(rps->cur_freq);
+	if (cur < ctx->min_freq)
+		schedule_work(&rps->work);
+}
+
 static void execlists_dequeue(struct intel_engine_cs *engine)
 {
 	struct intel_engine_execlists * const execlists = &engine->execlists;
@@ -697,6 +720,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 	if (submit) {
 		execlists_set_active(execlists, EXECLISTS_ACTIVE_USER);
 		execlists_submit_ports(engine);
+		update_gpufreq(engine);
 	}
 }
 
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 01983148862f..496410b4e6d0 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1463,9 +1463,18 @@ struct drm_i915_gem_context_param {
 #define   I915_CONTEXT_MAX_USER_PRIORITY	1023 /* inclusive */
 #define   I915_CONTEXT_DEFAULT_PRIORITY		0
 #define   I915_CONTEXT_MIN_USER_PRIORITY	-1023 /* inclusive */
+#define I915_CONTEXT_PARAM_FREQUENCY	0x7
 	__u64 value;
 };
 
+struct drm_i915_gem_context_frequency {
+	u32 min_frequency_mhz;
+	u32 max_frequency_mhz;
+	u32 flags;
+#define I915_CONTEXT_FREQUENCY_IMMEDIATE 0x1
+	u32 pad;
+};
+
 enum drm_i915_oa_format {
 	I915_OA_FORMAT_A13 = 1,	    /* HSW only */
 	I915_OA_FORMAT_A29,	    /* HSW only */
-- 
2.15.1



More information about the Intel-gfx-trybot mailing list