mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
msm: kgsl: Add a power constraints interface
Add an interface to hint the user specified power constraint. User can specify a particular GPU power level or a bandwidth vote. The power constraints are per context or command batch. Power constraints are only for hinting and should be used judiciously. Change-Id: Ic10a5fff4abc88c51cd45a7d7ac58c0d4e5dcb25 Signed-off-by: Suman Tatiraju <sumant@codeaurora.org> Signed-off-by: Lucille Sylvester <lsylvest@codeaurora.org>
This commit is contained in:
parent
dbfb277e44
commit
eeb3ca12b7
11 changed files with 284 additions and 12 deletions
|
@ -2226,12 +2226,65 @@ static int adreno_getproperty(struct kgsl_device *device,
|
|||
return status;
|
||||
}
|
||||
|
||||
static int adreno_setproperty(struct kgsl_device *device,
|
||||
static int adreno_set_constraint(struct kgsl_device *device,
|
||||
struct kgsl_context *context,
|
||||
struct kgsl_device_constraint *constraint)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
switch (constraint->type) {
|
||||
case KGSL_CONSTRAINT_PWRLEVEL: {
|
||||
struct kgsl_device_constraint_pwrlevel pwr;
|
||||
|
||||
if (constraint->size != sizeof(pwr)) {
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_from_user(&pwr,
|
||||
(void __user *)constraint->data,
|
||||
sizeof(pwr))) {
|
||||
status = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS) {
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
context->pwr_constraint.type =
|
||||
KGSL_CONSTRAINT_PWRLEVEL;
|
||||
context->pwr_constraint.sub_type = pwr.level;
|
||||
trace_kgsl_user_pwrlevel_constraint(device,
|
||||
context->id,
|
||||
context->pwr_constraint.type,
|
||||
context->pwr_constraint.sub_type);
|
||||
}
|
||||
break;
|
||||
case KGSL_CONSTRAINT_NONE:
|
||||
if (context->pwr_constraint.type == KGSL_CONSTRAINT_PWRLEVEL)
|
||||
trace_kgsl_user_pwrlevel_constraint(device,
|
||||
context->id,
|
||||
KGSL_CONSTRAINT_NONE,
|
||||
context->pwr_constraint.sub_type);
|
||||
context->pwr_constraint.type = KGSL_CONSTRAINT_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int adreno_setproperty(struct kgsl_device_private *dev_priv,
|
||||
enum kgsl_property_type type,
|
||||
void *value,
|
||||
unsigned int sizebytes)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
|
||||
switch (type) {
|
||||
|
@ -2260,6 +2313,28 @@ static int adreno_setproperty(struct kgsl_device *device,
|
|||
status = 0;
|
||||
}
|
||||
break;
|
||||
case KGSL_PROP_PWR_CONSTRAINT: {
|
||||
struct kgsl_device_constraint constraint;
|
||||
struct kgsl_context *context;
|
||||
|
||||
if (sizebytes != sizeof(constraint))
|
||||
break;
|
||||
|
||||
if (copy_from_user(&constraint, value,
|
||||
sizeof(constraint))) {
|
||||
status = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
context = kgsl_context_get_owner(dev_priv,
|
||||
constraint.context_id);
|
||||
if (context == NULL)
|
||||
break;
|
||||
status = adreno_set_constraint(device, context,
|
||||
&constraint);
|
||||
kgsl_context_put(context);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -429,7 +429,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
|
|||
KGSL_CONTEXT_PER_CONTEXT_TS |
|
||||
KGSL_CONTEXT_USER_GENERATED_TS |
|
||||
KGSL_CONTEXT_NO_FAULT_TOLERANCE |
|
||||
KGSL_CONTEXT_TYPE_MASK);
|
||||
KGSL_CONTEXT_TYPE_MASK |
|
||||
KGSL_CONTEXT_PWR_CONSTRAINT);
|
||||
|
||||
/* Always enable per-context timestamps */
|
||||
*flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
|
||||
|
@ -444,6 +445,9 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
|
|||
if (*flags & KGSL_CONTEXT_USER_GENERATED_TS)
|
||||
drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
|
||||
|
||||
if (*flags & KGSL_CONTEXT_PWR_CONSTRAINT)
|
||||
drawctxt->flags |= CTXT_FLAGS_PWR_CONSTRAINT;
|
||||
|
||||
mutex_init(&drawctxt->mutex);
|
||||
init_waitqueue_head(&drawctxt->wq);
|
||||
init_waitqueue_head(&drawctxt->waiting);
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16)
|
||||
/* Force the preamble for the next submission */
|
||||
#define CTXT_FLAGS_FORCE_PREAMBLE BIT(17)
|
||||
/* power constraints enabled */
|
||||
#define CTXT_FLAGS_PWR_CONSTRAINT BIT(18)
|
||||
|
||||
/* Symbolic table for the adreno draw context type */
|
||||
#define ADRENO_DRAWCTXT_TYPES \
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -987,6 +987,67 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
unsigned int adreno_ringbuffer_get_constraint(struct kgsl_device *device,
|
||||
struct kgsl_context *context)
|
||||
{
|
||||
unsigned int pwrlevel = device->pwrctrl.active_pwrlevel;
|
||||
|
||||
switch (context->pwr_constraint.type) {
|
||||
case KGSL_CONSTRAINT_PWRLEVEL: {
|
||||
switch (context->pwr_constraint.sub_type) {
|
||||
case KGSL_CONSTRAINT_PWR_MAX:
|
||||
pwrlevel = device->pwrctrl.max_pwrlevel;
|
||||
break;
|
||||
case KGSL_CONSTRAINT_PWR_MIN:
|
||||
pwrlevel = device->pwrctrl.min_pwrlevel;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return pwrlevel;
|
||||
}
|
||||
|
||||
void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
|
||||
struct kgsl_cmdbatch *cmdbatch)
|
||||
{
|
||||
unsigned int constraint;
|
||||
struct kgsl_context *context = cmdbatch->context;
|
||||
struct adreno_context *drawctxt;
|
||||
drawctxt = ADRENO_CONTEXT(context);
|
||||
/*
|
||||
* Check if the context has a constraint and constraint flags are
|
||||
* set.
|
||||
*/
|
||||
if (context->pwr_constraint.type &&
|
||||
((drawctxt->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
|
||||
(cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
|
||||
|
||||
constraint = adreno_ringbuffer_get_constraint(device, context);
|
||||
|
||||
/*
|
||||
* If a constraint is already set, set a new
|
||||
* constraint only if it is faster
|
||||
*/
|
||||
if ((device->pwrctrl.constraint.type ==
|
||||
KGSL_CONSTRAINT_NONE) || (constraint <
|
||||
device->pwrctrl.constraint.hint.pwrlevel.level)) {
|
||||
|
||||
kgsl_pwrctrl_pwrlevel_change(device, constraint);
|
||||
device->pwrctrl.constraint.type =
|
||||
context->pwr_constraint.type;
|
||||
device->pwrctrl.constraint.hint.
|
||||
pwrlevel.level = constraint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
|
||||
int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
|
||||
struct kgsl_cmdbatch *cmdbatch)
|
||||
|
@ -1094,6 +1155,9 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
|
|||
test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
|
||||
flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
|
||||
|
||||
/* Set the constraints before adding to ringbuffer */
|
||||
adreno_ringbuffer_set_constraint(device, cmdbatch);
|
||||
|
||||
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
|
||||
drawctxt,
|
||||
flags,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define TRACE_INCLUDE_FILE adreno_trace
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "kgsl_device.h"
|
||||
|
||||
TRACE_EVENT(adreno_cmdbatch_queued,
|
||||
TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued),
|
||||
|
@ -264,6 +265,36 @@ TRACE_EVENT(adreno_gpu_fault,
|
|||
__entry->ib2base, __entry->ib2size)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kgsl_user_pwrlevel_constraint,
|
||||
|
||||
TP_PROTO(struct kgsl_device *device, unsigned int id, unsigned int type,
|
||||
unsigned int sub_type),
|
||||
|
||||
TP_ARGS(device, id, type, sub_type),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device_name, device->name)
|
||||
__field(unsigned int, id)
|
||||
__field(unsigned int, type)
|
||||
__field(unsigned int, sub_type)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device_name, device->name);
|
||||
__entry->id = id;
|
||||
__entry->type = type;
|
||||
__entry->sub_type = sub_type;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"d_name=%s ctx=%u constraint_type=%s constraint_subtype=%s",
|
||||
__get_str(device_name), __entry->id,
|
||||
__print_symbolic(__entry->type, KGSL_CONSTRAINT_TYPES),
|
||||
__print_symbolic(__entry->sub_type,
|
||||
KGSL_CONSTRAINT_PWRLEVEL_SUBTYPES)
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _ADRENO_TRACE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
@ -1397,8 +1397,8 @@ static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
|
|||
|
||||
if (dev_priv->device->ftbl->setproperty)
|
||||
result = dev_priv->device->ftbl->setproperty(
|
||||
dev_priv->device, param->type,
|
||||
param->value, param->sizebytes);
|
||||
dev_priv, param->type, param->value,
|
||||
param->sizebytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -127,8 +127,8 @@ struct kgsl_functable {
|
|||
void (*drawctxt_destroy) (struct kgsl_context *context);
|
||||
long (*ioctl) (struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data);
|
||||
int (*setproperty) (struct kgsl_device *device,
|
||||
enum kgsl_property_type type, void *value,
|
||||
int (*setproperty) (struct kgsl_device_private *dev_priv,
|
||||
enum kgsl_property_type type, void __user *value,
|
||||
unsigned int sizebytes);
|
||||
int (*postmortem_dump) (struct kgsl_device *device, int manual);
|
||||
void (*drawctxt_sched)(struct kgsl_device *device,
|
||||
|
@ -361,7 +361,7 @@ struct kgsl_process_private;
|
|||
* is set.
|
||||
* @fault_count: number of times gpu hanged in last _context_throttle_time ms
|
||||
* @fault_time: time of the first gpu hang in last _context_throttle_time ms
|
||||
>>>>>>> 28ee7f6... msm: kgsl: Enhance GFT to avoid hang->recover->hang cycle
|
||||
* @pwr_constraint: power constraint from userspace for this context
|
||||
*/
|
||||
struct kgsl_context {
|
||||
struct kref refcount;
|
||||
|
@ -379,6 +379,7 @@ struct kgsl_context {
|
|||
unsigned int pagefault_ts;
|
||||
unsigned int fault_count;
|
||||
unsigned long fault_time;
|
||||
struct kgsl_pwr_constraint pwr_constraint;
|
||||
};
|
||||
|
||||
struct kgsl_process_private {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -27,6 +27,18 @@
|
|||
|
||||
#define KGSL_MAX_CLKS 6
|
||||
|
||||
/* Only two supported levels, min & max */
|
||||
#define KGSL_CONSTRAINT_PWR_MAXLEVELS 2
|
||||
|
||||
/* Symbolic table for the constraint type */
|
||||
#define KGSL_CONSTRAINT_TYPES \
|
||||
{ KGSL_CONSTRAINT_NONE, "None" }, \
|
||||
{ KGSL_CONSTRAINT_PWRLEVEL, "Pwrlevel" }
|
||||
/* Symbolic table for the constraint sub type */
|
||||
#define KGSL_CONSTRAINT_PWRLEVEL_SUBTYPES \
|
||||
{ KGSL_CONSTRAINT_PWR_MIN, "Min" }, \
|
||||
{ KGSL_CONSTRAINT_PWR_MAX, "Max" }
|
||||
|
||||
struct platform_device;
|
||||
|
||||
struct kgsl_clk_stats {
|
||||
|
@ -40,6 +52,16 @@ struct kgsl_clk_stats {
|
|||
unsigned int elapsed_old;
|
||||
};
|
||||
|
||||
struct kgsl_pwr_constraint {
|
||||
unsigned int type;
|
||||
unsigned int sub_type;
|
||||
union {
|
||||
struct {
|
||||
unsigned int level;
|
||||
} pwrlevel;
|
||||
} hint;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kgsl_pwrctrl - Power control settings for a KGSL device
|
||||
* @interrupt_num - The interrupt number for the device
|
||||
|
@ -65,6 +87,7 @@ struct kgsl_clk_stats {
|
|||
* @pm_qos_req_dma - the power management quality of service structure
|
||||
* @pm_qos_latency - allowed CPU latency in microseconds
|
||||
* @step_mul - multiplier for moving between power levels
|
||||
* @constraint - currently active power constraint
|
||||
*/
|
||||
|
||||
struct kgsl_pwrctrl {
|
||||
|
@ -94,6 +117,7 @@ struct kgsl_pwrctrl {
|
|||
unsigned int pm_qos_latency;
|
||||
unsigned int step_mul;
|
||||
unsigned int irq_last;
|
||||
struct kgsl_pwr_constraint constraint;
|
||||
};
|
||||
|
||||
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "kgsl.h"
|
||||
#include "kgsl_pwrscale.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
#define TZ_GOVERNOR_PERFORMANCE 0
|
||||
#define TZ_GOVERNOR_ONDEMAND 1
|
||||
|
@ -187,9 +188,19 @@ static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
|
|||
*/
|
||||
if (val > 0)
|
||||
val *= pwr->step_mul;
|
||||
if (val)
|
||||
|
||||
if (val) {
|
||||
kgsl_pwrctrl_pwrlevel_change(device,
|
||||
pwr->active_pwrlevel + val);
|
||||
if (pwr->constraint.type != KGSL_CONSTRAINT_NONE) {
|
||||
/* Trace the constraint being un-set by the driver */
|
||||
trace_kgsl_constraint(device,
|
||||
pwr->constraint.type,
|
||||
pwr->active_pwrlevel, 0);
|
||||
/*Invalidate the constraint set */
|
||||
pwr->constraint.type = KGSL_CONSTRAINT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tz_busy(struct kgsl_device *device,
|
||||
|
|
|
@ -676,6 +676,36 @@ TRACE_EVENT(kgsl_context_destroy,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kgsl_constraint,
|
||||
|
||||
TP_PROTO(struct kgsl_device *device, unsigned int type,
|
||||
unsigned int value, unsigned int on),
|
||||
|
||||
TP_ARGS(device, type, value, on),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device_name, device->name)
|
||||
__field(unsigned int, type)
|
||||
__field(unsigned int, value)
|
||||
__field(unsigned int, on)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device_name, device->name);
|
||||
__entry->type = type;
|
||||
__entry->value = value;
|
||||
__entry->on = on;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"d_name=%s constraint_type=%s constraint_value=%u status=%s",
|
||||
__get_str(device_name),
|
||||
__print_symbolic(__entry->type, KGSL_CONSTRAINT_TYPES),
|
||||
__entry->value,
|
||||
__entry->on ? "ON" : "OFF"
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kgsl_mmu_pagefault,
|
||||
|
||||
TP_PROTO(struct kgsl_device *device, unsigned int page,
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
|
||||
#define KGSL_CONTEXT_SYNC 0x00000400
|
||||
#define KGSL_CONTEXT_PWR_CONSTRAINT 0x00000800
|
||||
/* bits [12:15] are reserved for future use */
|
||||
#define KGSL_CONTEXT_TYPE_MASK 0x01F00000
|
||||
#define KGSL_CONTEXT_TYPE_SHIFT 20
|
||||
|
@ -196,6 +197,7 @@ enum kgsl_property_type {
|
|||
KGSL_PROP_VERSION = 0x00000008,
|
||||
KGSL_PROP_GPU_RESET_STAT = 0x00000009,
|
||||
KGSL_PROP_PWRCTRL = 0x0000000E,
|
||||
KGSL_PROP_PWR_CONSTRAINT = 0x00000012,
|
||||
};
|
||||
|
||||
struct kgsl_shadowprop {
|
||||
|
@ -883,6 +885,34 @@ struct kgsl_submit_commands {
|
|||
#define IOCTL_KGSL_SUBMIT_COMMANDS \
|
||||
_IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
|
||||
|
||||
/**
|
||||
* struct kgsl_device_constraint - device constraint argument
|
||||
* @context_id: KGSL context ID
|
||||
* @type: type of constraint i.e pwrlevel/none
|
||||
* @data: constraint data
|
||||
* @size: size of the constraint data
|
||||
*/
|
||||
struct kgsl_device_constraint {
|
||||
unsigned int type;
|
||||
unsigned int context_id;
|
||||
void __user *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Constraint Type*/
|
||||
#define KGSL_CONSTRAINT_NONE 0
|
||||
#define KGSL_CONSTRAINT_PWRLEVEL 1
|
||||
|
||||
/* PWRLEVEL constraint level*/
|
||||
/* set to min frequency */
|
||||
#define KGSL_CONSTRAINT_PWR_MIN 0
|
||||
/* set to max frequency */
|
||||
#define KGSL_CONSTRAINT_PWR_MAX 1
|
||||
|
||||
struct kgsl_device_constraint_pwrlevel {
|
||||
unsigned int level;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#ifdef CONFIG_MSM_KGSL_DRM
|
||||
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
|
||||
|
|
Loading…
Reference in a new issue