[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