msm: dcvs: remove core name.

Currently core_name is used to identify which core the dcvs operates on.
Instead use a type and the type num while registration with dcvs and
return an id (dcvs_core_id) upon successfull registration.

The dcvs_core_id is used by the clients of msm_dcvs to call upon its
apis viz. freq_start, freq_stop, msm_dcvs_idle etc.

The dcvs inturn uses the type num passed in at registration time to
invoke apis on the clients viz. set_freq, get_freq, idle_enable.

This further cleans up the internal dcvs add_core and get_core
implementation. One need not pass around the core_name and use the type
instead.

Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
(cherry picked from commit 1bbc0321a6871e018c17da6f244b9df442faead6)

Signed-off-by: Ram Kumar Chakravarthy Chebathini <rcheba@codeaurora.org>
(cherry picked from commit 09456d7d7618e6d0fc6b907b7af75268ea08a942)

Change-Id: Id27751a8ec8f5d3d386bbe7c7625ed56757b8bd7
Signed-off-by: Sudhir Sharma <sudsha@codeaurora.org>
This commit is contained in:
Abhijeet Dharmapurikar 2012-09-12 16:40:20 -07:00 committed by Stephen Boyd
parent e9fe87f613
commit 404a619d85
4 changed files with 217 additions and 346 deletions

View file

@ -19,6 +19,10 @@
#define CORES_MAX (10)
#define CPU_OFFSET 1 /* used to notify TZ the core number */
#define GPU_OFFSET (CORES_MAX * 2/3) /* there will be more cpus than gpus,
* let the GPU be assigned fewer core
* elements and start later
*/
enum msm_core_idle_state {
MSM_DCVS_IDLE_ENTER,
@ -32,56 +36,14 @@ enum msm_core_control_event {
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
};
/**
* struct msm_dcvs_idle
*
* API for idle code to register and send idle enter/exit
* notifications to msm_dcvs driver.
*/
struct msm_dcvs_idle {
const char *core_name;
};
struct msm_gov_platform_data {
struct msm_dcvs_core_info *info;
int latency;
};
/**
* struct msm_dcvs_freq
*
* API for clock driver code to register and receive frequency change
* request for the core from the msm_dcvs driver.
*/
struct msm_dcvs_freq {
const char *core_name;
/* Callback from msm_dcvs to set the core frequency */
};
/**
* msm_dcvs_idle_source_register
* @drv: Pointer to the source driver
* @return: Handle to be used for sending idle state notifications.
*
* Register the idle driver with the msm_dcvs driver to send idle
* state notifications for the core.
*/
extern int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv);
/**
* msm_dcvs_idle_source_unregister
* @drv: Pointer to the source driver
* @return:
* 0 on success
* -EINVAL
*
* Description: Unregister the idle driver with the msm_dcvs driver
*/
extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
/**
* msm_dcvs_idle
* @handle: Handle provided back at registration
* @dcvs_core_id: The id returned by msm_dcvs_register_core
* @state: The enter/exit idle state the core is in
* @iowaited: iowait in us
* on iMSM_DCVS_IDLE_EXIT.
@ -93,7 +55,7 @@ extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
*
* Send idle state notifications to the msm_dcvs driver
*/
int msm_dcvs_idle(int handle, enum msm_core_idle_state state,
int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
uint32_t iowaited);
/**
@ -114,7 +76,8 @@ struct msm_dcvs_core_info {
/**
* msm_dcvs_register_core
* @core_name: Unique name identifier for the core.
* @type: whether this is a CPU or a GPU
* @type_core_num: The number of the core for a type
* @info: The core specific algorithm parameters.
* @sensor: The thermal sensor number of the core in question
* @return :
@ -127,11 +90,12 @@ struct msm_dcvs_core_info {
* Cores that need to run synchronously must share the same group id.
*/
extern int msm_dcvs_register_core(
const char *core_name,
enum msm_dcvs_core_type type,
int type_core_num,
struct msm_dcvs_core_info *info,
int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
int (*idle_enable)(struct msm_dcvs_idle *self,
int (*set_frequency)(int type_core_num, unsigned int freq),
unsigned int (*get_frequency)(int type_core_num),
int (*idle_enable)(int type_core_num,
enum msm_core_control_event event),
int sensor);
@ -143,7 +107,7 @@ extern int msm_dcvs_register_core(
* Register the clock driver code with the msm_dvs driver to get notified about
* frequency change requests.
*/
extern int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv);
extern int msm_dcvs_freq_sink_start(int dcvs_core_id);
/**
* msm_dcvs_freq_sink_stop
@ -155,7 +119,7 @@ extern int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv);
* Unregister the sink driver for the core. This will cause the source driver
* for the core to stop sending idle pulses.
*/
extern int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv);
extern int msm_dcvs_freq_sink_stop(int dcvs_core_id);
/**
* msm_dcvs_update_limits
@ -163,5 +127,5 @@ extern int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv);
*
* Update the frequency known to dcvs when the limits are changed.
*/
extern void msm_dcvs_update_limits(struct msm_dcvs_freq *drv);
extern void msm_dcvs_update_limits(int dcvs_core_id);
#endif

View file

@ -73,6 +73,9 @@ struct core_attribs {
};
struct dcvs_core {
enum msm_dcvs_core_type type;
/* this is the number in each type for example cpu 0,1,2 and gpu 0,1 */
int type_core_num;
char core_name[CORE_NAME_MAX];
uint32_t actual_freq;
uint32_t freq_change_us;
@ -81,8 +84,6 @@ struct dcvs_core {
struct msm_dcvs_algo_param algo_param;
struct msm_dcvs_energy_curve_coeffs coeffs;
struct msm_dcvs_idle *idle_driver;
struct msm_dcvs_freq *freq_driver;
/* private */
int64_t time_start;
@ -90,16 +91,17 @@ struct dcvs_core {
spinlock_t cpu_lock;
struct task_struct *task;
struct core_attribs attrib;
uint32_t handle;
uint32_t dcvs_core_id;
struct hrtimer timer;
int32_t timer_disabled;
struct msm_dcvs_core_info *info;
int sensor;
int pending_freq;
wait_queue_head_t wait_q;
int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq);
unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
int (*idle_enable)(struct msm_dcvs_idle *self,
int (*set_frequency)(int type_core_num, unsigned int freq);
unsigned int (*get_frequency)(int type_core_num);
int (*idle_enable)(int type_core_num,
enum msm_core_control_event event);
};
@ -110,10 +112,8 @@ module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
static struct dentry *debugfs_base;
static struct dcvs_core core_list[CORES_MAX];
static DEFINE_MUTEX(core_list_lock);
static struct kobject *cores_kobj;
static struct dcvs_core *core_handles[CORES_MAX];
/* Change core frequency, called with core mutex locked */
static int __msm_dcvs_change_freq(struct dcvs_core *core)
@ -127,7 +127,7 @@ static int __msm_dcvs_change_freq(struct dcvs_core *core)
uint32_t slack_us = 0;
uint32_t ret1 = 0;
if (!core->freq_driver || !core->set_frequency) {
if (!core->set_frequency) {
/* Core may have unregistered or hotplugged */
return -ENODEV;
}
@ -155,7 +155,7 @@ repeat:
* We will need to get back the actual frequency in KHz and
* the record the time taken to change it.
*/
ret = core->set_frequency(core->freq_driver, requested_freq);
ret = core->set_frequency(core->type_core_num, requested_freq);
if (ret <= 0) {
__err("Core %s failed to set freq %u\n",
core->core_name, requested_freq);
@ -177,15 +177,14 @@ repeat:
* Disable low power modes if the actual frequency is >
* disable_pc_threshold.
*/
if (core->actual_freq >
core->algo_param.disable_pc_threshold) {
core->idle_enable(core->idle_driver,
if (core->actual_freq > core->algo_param.disable_pc_threshold) {
core->idle_enable(core->type_core_num,
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Disabling LPM for %s\n", core->core_name);
} else if (core->actual_freq <=
core->algo_param.disable_pc_threshold) {
core->idle_enable(core->idle_driver,
core->idle_enable(core->type_core_num,
MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Enabling LPM for %s\n", core->core_name);
@ -196,8 +195,10 @@ repeat:
* to this frequency and that will get us the new slack
* timer
*/
ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
core->actual_freq, (uint32_t)time_end, &slack_us, &ret1);
ret = msm_dcvs_scm_event(core->dcvs_core_id,
MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
core->actual_freq, (uint32_t)time_end,
&slack_us, &ret1);
if (!ret) {
/* Reset the slack timer */
if (slack_us) {
@ -253,7 +254,8 @@ static int __msm_dcvs_report_temp(struct dcvs_core *core)
return -ENODEV;
}
ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
&info->power_param,
&info->freq_tbl[0], &core->coeffs);
return ret;
}
@ -291,7 +293,7 @@ static int msm_dcvs_update_freq(struct dcvs_core *core,
uint32_t new_freq = 0;
spin_lock_irqsave(&core->cpu_lock, flags);
ret = msm_dcvs_scm_event(core->handle, event, param0,
ret = msm_dcvs_scm_event(core->dcvs_core_id, event, param0,
core->actual_freq, &new_freq, ret1);
if (ret) {
if (ret == -13)
@ -374,7 +376,7 @@ static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
} else { \
uint32_t old_val = core->algo_param._name; \
core->algo_param._name = val; \
ret = msm_dcvs_scm_set_algo_params(core->handle, \
ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id, \
&core->algo_param); \
if (ret) { \
core->algo_param._name = old_val; \
@ -406,7 +408,7 @@ static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
} else { \
int32_t old_val = core->coeffs._name; \
core->coeffs._name = val; \
ret = msm_dcvs_scm_set_power_params(core->handle, \
ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id, \
&core->info->power_param, &core->info->freq_tbl[0], \
&core->coeffs); \
if (ret) { \
@ -437,9 +439,9 @@ static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
* Function declarations for different attributes.
* Gets used when setting the attribute show and store parameters.
*/
DCVS_PARAM_SHOW(core_id, core->handle)
DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
DCVS_PARAM_SHOW(core_id, core->dcvs_core_id)
DCVS_PARAM_SHOW(idle_enabled, (core->idle_enable != NULL))
DCVS_PARAM_SHOW(freq_change_enabled, (core->set_frequency != NULL))
DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
@ -535,107 +537,71 @@ done:
return ret;
}
/* Return the core if found or add to list if @add_to_list is true */
static struct dcvs_core *msm_dcvs_add_core(const char *name, int *pos)
/* Return the core and initialize non platform data specific numbers in it */
static struct dcvs_core *msm_dcvs_add_core(enum msm_dcvs_core_type type,
int num)
{
struct dcvs_core *core = NULL;
int i;
int empty = -1;
char name[CORE_NAME_MAX];
if (!name[0] ||
(strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
return core;
switch (type) {
case MSM_DCVS_CORE_TYPE_CPU:
i = CPU_OFFSET + num;
BUG_ON(i >= GPU_OFFSET);
snprintf(name, CORE_NAME_MAX, "cpu%d", num);
break;
case MSM_DCVS_CORE_TYPE_GPU:
i = GPU_OFFSET + num;
BUG_ON(i >= CORES_MAX);
snprintf(name, CORE_NAME_MAX, "gpu%d", num);
break;
default:
return NULL;
}
mutex_lock(&core_list_lock);
for (i = 0; i < CORES_MAX; i++) {
core = &core_list[i];
if ((empty < 0) && !core->core_name[0]) {
empty = i;
continue;
}
if (!strncmp(name, core->core_name, CORE_NAME_MAX)) {
if (pos != NULL)
*pos = i;
/*
* found a core with the same name, return NULL and
* set pos
*/
core = NULL;
goto out;
}
}
/* Check for core_list full */
if (empty < 0) {
*pos = 0;
core = NULL;
goto out;
}
core = &core_list[empty];
core->dcvs_core_id = i;
strlcpy(core->core_name, name, CORE_NAME_MAX);
mutex_init(&core->lock);
spin_lock_init(&core->cpu_lock);
core->handle = empty + CORE_HANDLE_OFFSET;
hrtimer_init(&core->timer,
CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
hrtimer_init(&core->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
core->timer.function = msm_dcvs_core_slack_timer;
if (pos != NULL)
*pos = empty;
out:
mutex_unlock(&core_list_lock);
return core;
}
/* Return the core if found or add to list if @add_to_list is true */
static struct dcvs_core *msm_dcvs_get_core(const char *name, int *pos)
static struct dcvs_core *msm_dcvs_get_core(int offset)
{
struct dcvs_core *core = NULL;
int i;
if (!name[0] ||
(strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
return core;
mutex_lock(&core_list_lock);
for (i = 0; i < CORES_MAX; i++) {
core = &core_list[i];
if (!strncmp(name, core->core_name, CORE_NAME_MAX)) {
if (pos != NULL)
*pos = i;
break;
}
}
mutex_unlock(&core_list_lock);
return core;
/* if the handle is still not set bug */
BUG_ON(core_list[offset].dcvs_core_id == -1);
return &core_list[offset];
}
int msm_dcvs_register_core(const char *core_name,
int msm_dcvs_register_core(
enum msm_dcvs_core_type type,
int type_core_num,
struct msm_dcvs_core_info *info,
int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
int (*idle_enable)(struct msm_dcvs_idle *self,
int (*set_frequency)(int type_core_num, unsigned int freq),
unsigned int (*get_frequency)(int type_core_num),
int (*idle_enable)(int type_core_num,
enum msm_core_control_event event),
int sensor)
{
int ret = -EINVAL;
int pos = 0;
struct dcvs_core *core = NULL;
uint32_t ret1;
uint32_t ret2;
if (!core_name || !core_name[0])
return ret;
core = msm_dcvs_add_core(core_name, &pos);
core = msm_dcvs_add_core(type, type_core_num);
if (!core)
return ret;
mutex_lock(&core->lock);
core->type = type;
core->type_core_num = type_core_num;
core->set_frequency = set_frequency;
core->get_frequency = get_frequency;
core->idle_enable = idle_enable;
@ -647,24 +613,39 @@ int msm_dcvs_register_core(const char *core_name,
memcpy(&core->coeffs, &info->energy_coeffs,
sizeof(struct msm_dcvs_energy_curve_coeffs));
info->core_param.core_bitmask_id = 1 << pos;
pr_debug("registering core with sensor %d\n", sensor);
/*
* The tz expects cpu0 to represent bit 0 in the mask, however the
* dcvs_core_id needs to start from 1, dcvs_core_id = 0 is used to
* indicate that this request is not associated with any core.
* mpdecision
*/
info->core_param.core_bitmask_id
= 1 << (core->dcvs_core_id - CPU_OFFSET);
core->sensor = sensor;
ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
if (ret)
ret = msm_dcvs_scm_register_core(core->dcvs_core_id, &info->core_param);
if (ret) {
__err("%s: scm register core fail handle = %d ret = %d\n",
__func__, core->dcvs_core_id, ret);
goto bail;
}
ret = msm_dcvs_scm_set_algo_params(core->handle, &info->algo_param);
if (ret)
ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id,
&info->algo_param);
if (ret) {
__err("%s: scm algo params failed ret = %d\n", __func__, ret);
goto bail;
}
ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
&info->power_param,
&info->freq_tbl[0], &core->coeffs);
if (ret)
if (ret) {
__err("%s: scm power params failed ret = %d\n", __func__, ret);
goto bail;
}
ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CORE_ONLINE,
ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_CORE_ONLINE,
core->actual_freq, 0, &ret1, &ret2);
if (ret)
goto bail;
@ -672,48 +653,53 @@ int msm_dcvs_register_core(const char *core_name,
ret = msm_dcvs_setup_core_sysfs(core);
if (ret) {
__err("Unable to setup core %s sysfs\n", core->core_name);
core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
goto bail;
}
init_waitqueue_head(&core->wait_q);
core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
"msm_dcvs/%d", core->handle);
bail:
"msm_dcvs/%d", core->dcvs_core_id);
ret = core->dcvs_core_id;
mutex_unlock(&core->lock);
return ret;
bail:
mutex_unlock(&core->lock);
core->dcvs_core_id = -1;
return -EINVAL;
}
EXPORT_SYMBOL(msm_dcvs_register_core);
void msm_dcvs_update_limits(struct msm_dcvs_freq *drv)
void msm_dcvs_update_limits(int dcvs_core_id)
{
struct dcvs_core *core;
if (!drv || !drv->core_name)
if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
__err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
__func__, dcvs_core_id);
return;
}
core = msm_dcvs_get_core(drv->core_name, NULL);
core->actual_freq = core->get_frequency(drv);
core = msm_dcvs_get_core(dcvs_core_id);
core->actual_freq = core->get_frequency(core->type_core_num);
}
int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv)
int msm_dcvs_freq_sink_start(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
uint32_t ret2;
if (!drv || !drv->core_name)
return ret;
if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
__err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
__func__, dcvs_core_id);
return -EINVAL;
}
core = msm_dcvs_get_core(drv->core_name, NULL);
core = msm_dcvs_get_core(dcvs_core_id);
if (!core)
return ret;
mutex_lock(&core->lock);
if (core->freq_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
__info("Frequency notifier for %s being replaced\n",
core->core_name);
core->freq_driver = drv;
if (IS_ERR(core->task)) {
mutex_unlock(&core->lock);
return -EFAULT;
@ -722,101 +708,56 @@ int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv)
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Enabling idle pulse for %s\n", core->core_name);
if (core->idle_driver) {
core->actual_freq = core->get_frequency(drv);
core->actual_freq = core->get_frequency(core->type_core_num);
/* Notify TZ to start receiving idle info for the core */
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
&ret1, &ret2);
core->idle_enable(core->idle_driver,
MSM_DCVS_ENABLE_IDLE_PULSE);
}
core->idle_enable(core->type_core_num, MSM_DCVS_ENABLE_IDLE_PULSE);
mutex_unlock(&core->lock);
return core->handle;
return core->dcvs_core_id;
}
EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv)
int msm_dcvs_freq_sink_stop(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
uint32_t ret2;
if (!drv || !drv->core_name)
return ret;
if (dcvs_core_id < 0 || dcvs_core_id > CORES_MAX) {
pr_err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
__func__, dcvs_core_id);
return -EINVAL;
}
core = msm_dcvs_get_core(drv->core_name, NULL);
core = msm_dcvs_get_core(dcvs_core_id);
if (!core)
return ret;
mutex_lock(&core->lock);
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Disabling idle pulse for %s\n", core->core_name);
if (core->idle_driver) {
core->idle_enable(core->idle_driver,
MSM_DCVS_DISABLE_IDLE_PULSE);
core->idle_enable(core->type_core_num, MSM_DCVS_DISABLE_IDLE_PULSE);
/* Notify TZ to stop receiving idle info for the core */
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 0,
&ret1, &ret2);
hrtimer_cancel(&core->timer);
core->idle_enable(core->idle_driver,
core->idle_enable(core->type_core_num,
MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Enabling LPM for %s\n", core->core_name);
}
core->freq_driver = NULL;
mutex_unlock(&core->lock);
return 0;
}
EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
if (!drv || !drv->core_name)
return ret;
core = msm_dcvs_get_core(drv->core_name, NULL);
if (!core)
return ret;
mutex_lock(&core->lock);
if (core->idle_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
__info("Idle notifier for %s being replaced\n",
core->core_name);
core->idle_driver = drv;
mutex_unlock(&core->lock);
return core->handle;
}
EXPORT_SYMBOL(msm_dcvs_idle_source_register);
int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
if (!drv || !drv->core_name)
return ret;
core = msm_dcvs_get_core(drv->core_name, NULL);
if (!core)
return ret;
mutex_lock(&core->lock);
core->idle_driver = NULL;
mutex_unlock(&core->lock);
return 0;
}
EXPORT_SYMBOL(msm_dcvs_idle_source_unregister);
int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
uint32_t iowaited)
{
int ret = 0;
struct dcvs_core *core = NULL;
@ -824,11 +765,12 @@ int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
uint32_t r0, r1;
uint32_t freq_changed = 0;
if (handle >= CORE_HANDLE_OFFSET &&
(handle - CORE_HANDLE_OFFSET) < CORES_MAX)
core = &core_list[handle - CORE_HANDLE_OFFSET];
if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
pr_err("invalid dcvs_core_id = %d ret -EINVAL\n", dcvs_core_id);
return -EINVAL;
}
BUG_ON(!core);
core = msm_dcvs_get_core(dcvs_core_id);
if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
__info("Core %s idle state %d\n", core->core_name, state);
@ -836,7 +778,7 @@ int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
switch (state) {
case MSM_DCVS_IDLE_ENTER:
hrtimer_cancel(&core->timer);
ret = msm_dcvs_scm_event(core->handle,
ret = msm_dcvs_scm_event(core->dcvs_core_id,
MSM_DCVS_SCM_IDLE_ENTER, 0, 0, &r0, &r1);
if (ret)
__err("Error (%d) sending idle enter for %s\n",
@ -917,6 +859,7 @@ late_initcall(msm_dcvs_late_init);
static int __init msm_dcvs_early_init(void)
{
int ret = 0;
int i;
if (!msm_dcvs_enabled) {
__info("Not enabled (%d)\n", msm_dcvs_enabled);
@ -927,6 +870,8 @@ static int __init msm_dcvs_early_init(void)
if (ret)
__err("Unable to initialize DCVS err=%d\n", ret);
for (i = 0; i < CORES_MAX; i++)
core_list[i].dcvs_core_id = -1;
return ret;
}
postcore_initcall(msm_dcvs_early_init);

View file

@ -25,23 +25,19 @@
#include <mach/msm_dcvs.h>
struct cpu_idle_info {
int cpu;
int enabled;
int handle;
struct msm_dcvs_idle dcvs_notifier;
int dcvs_core_id;
struct pm_qos_request pm_qos_req;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
static char core_name[NR_CPUS][10];
static uint32_t latency;
static int msm_dcvs_idle_notifier(struct msm_dcvs_idle *self,
static int msm_dcvs_idle_notifier(int core_num,
enum msm_core_control_event event)
{
struct cpu_idle_info *info = container_of(self,
struct cpu_idle_info, dcvs_notifier);
struct cpu_idle_info *info = &per_cpu(cpu_idle_info, core_num);
switch (event) {
case MSM_DCVS_ENABLE_IDLE_PULSE:
@ -86,7 +82,7 @@ static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
if (val == (u64)-1)
val = 0;
per_cpu(iowait_on_cpu, smp_processor_id()) = val;
msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_ENTER, 0);
msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
break;
case CPU_PM_EXIT:
@ -97,7 +93,7 @@ static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
val = 0;
io_wait_us = val;
iowaited = (io_wait_us - prev_io_wait_us);
msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_EXIT, iowaited);
msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_EXIT, iowaited);
break;
}
@ -108,52 +104,32 @@ static struct notifier_block idle_nb = {
.notifier_call = msm_cpuidle_notifier,
};
static void msm_gov_idle_source_init(int cpu)
static void msm_gov_idle_source_init(int cpu, int dcvs_core_id)
{
struct cpu_idle_info *info = NULL;
struct msm_dcvs_idle *inotify = NULL;
info = &per_cpu(cpu_idle_info, cpu);
info->cpu = cpu;
inotify = &info->dcvs_notifier;
snprintf(core_name[cpu], 10, "cpu%d", cpu);
inotify->core_name = core_name[cpu];
info->handle = msm_dcvs_idle_source_register(inotify);
BUG_ON(info->handle < 0);
info->dcvs_core_id = dcvs_core_id;
pm_qos_add_request(&info->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
}
static int msm_gov_idle_source_uninit(int cpu)
{
struct cpu_idle_info *info = NULL;
struct msm_dcvs_idle *inotify = NULL;
info = &per_cpu(cpu_idle_info, cpu);
info->cpu = cpu;
inotify = &info->dcvs_notifier;
return msm_dcvs_idle_source_unregister(inotify);
}
struct msm_gov {
int cpu;
unsigned int cur_freq;
unsigned int min_freq;
unsigned int max_freq;
struct msm_dcvs_freq gov_notifier;
struct cpufreq_policy *policy;
int dcvs_core_id;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct mutex, gov_mutex);
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_gov, msm_gov_info);
static char core_name[NR_CPUS][10];
static void msm_gov_check_limits(struct cpufreq_policy *policy)
{
struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
struct msm_dcvs_freq *dcvs_notifier =
&(per_cpu(msm_gov_info, policy->cpu).gov_notifier);
if (policy->max < gov->cur_freq)
__cpufreq_driver_target(policy, policy->max,
@ -168,15 +144,14 @@ static void msm_gov_check_limits(struct cpufreq_policy *policy)
gov->cur_freq = policy->cur;
gov->min_freq = policy->min;
gov->max_freq = policy->max;
msm_dcvs_update_limits(dcvs_notifier);
msm_dcvs_update_limits(gov->dcvs_core_id);
}
static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
static int msm_dcvs_freq_set(int core_num,
unsigned int freq)
{
int ret = -EINVAL;
struct msm_gov *gov =
container_of(self, struct msm_gov, gov_notifier);
struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
mutex_lock(&per_cpu(gov_mutex, gov->cpu));
@ -200,11 +175,9 @@ static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
return ret;
}
static unsigned int msm_dcvs_freq_get(struct msm_dcvs_freq *self)
static unsigned int msm_dcvs_freq_get(int core_num)
{
struct msm_gov *gov =
container_of(self, struct msm_gov, gov_notifier);
struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
/*
* the rw_sem in cpufreq is always held when this is called.
* The policy->cur won't be updated in this case - so it is safe to
@ -220,8 +193,6 @@ static int cpufreq_governor_msm(struct cpufreq_policy *policy,
int ret = 0;
int handle = 0;
struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
struct msm_dcvs_freq *dcvs_notifier =
&(per_cpu(msm_gov_info, cpu).gov_notifier);
switch (event) {
case CPUFREQ_GOV_START:
@ -231,15 +202,14 @@ static int cpufreq_governor_msm(struct cpufreq_policy *policy,
mutex_lock(&per_cpu(gov_mutex, cpu));
per_cpu(msm_gov_info, cpu).cpu = cpu;
gov->policy = policy;
dcvs_notifier->core_name = core_name[cpu];
handle = msm_dcvs_freq_sink_start(dcvs_notifier);
handle = msm_dcvs_freq_sink_start(gov->dcvs_core_id);
BUG_ON(handle < 0);
msm_gov_check_limits(policy);
mutex_unlock(&per_cpu(gov_mutex, cpu));
break;
case CPUFREQ_GOV_STOP:
msm_dcvs_freq_sink_stop(dcvs_notifier);
msm_dcvs_freq_sink_stop(gov->dcvs_core_id);
break;
case CPUFREQ_GOV_LIMITS:
@ -260,7 +230,6 @@ struct cpufreq_governor cpufreq_gov_msm = {
static int __devinit msm_gov_probe(struct platform_device *pdev)
{
int ret = 0;
int cpu;
struct msm_dcvs_core_info *core = NULL;
struct msm_dcvs_core_info *core_info = NULL;
@ -272,19 +241,25 @@ static int __devinit msm_gov_probe(struct platform_device *pdev)
latency = pdata->latency;
for_each_possible_cpu(cpu) {
struct msm_gov *gov = &per_cpu(msm_gov_info, cpu);
mutex_init(&per_cpu(gov_mutex, cpu));
snprintf(core_name[cpu], 10, "cpu%d", cpu);
if (cpu < core->num_cores)
sensor = core_info->sensors[cpu];
ret = msm_dcvs_register_core(core_name[cpu], core_info,
gov->dcvs_core_id = msm_dcvs_register_core(
MSM_DCVS_CORE_TYPE_CPU,
cpu,
core_info,
msm_dcvs_freq_set,
msm_dcvs_freq_get,
msm_dcvs_idle_notifier,
sensor);
if (ret)
if (gov->dcvs_core_id < 0) {
pr_err("Unable to register core for %d\n", cpu);
return -EINVAL;
}
msm_gov_idle_source_init(cpu);
msm_gov_idle_source_init(cpu, gov->dcvs_core_id);
}
cpu_pm_register_notifier(&idle_nb);
@ -294,11 +269,6 @@ static int __devinit msm_gov_probe(struct platform_device *pdev)
static int __devexit msm_gov_remove(struct platform_device *pdev)
{
int cpu;
for_each_possible_cpu(cpu) {
msm_gov_idle_source_uninit(cpu);
}
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -22,19 +22,19 @@
struct msm_priv {
struct kgsl_device *device;
int enabled;
int handle;
unsigned int cur_freq;
struct msm_dcvs_idle idle_source;
struct msm_dcvs_freq freq_sink;
struct msm_dcvs_core_info *core_info;
int gpu_busy;
int dcvs_core_id;
};
static int msm_idle_enable(struct msm_dcvs_idle *self,
/* reference to be used in idle and freq callbacks */
static struct msm_priv *the_msm_priv;
static int msm_idle_enable(int type_core_num,
enum msm_core_control_event event)
{
struct msm_priv *priv = container_of(self, struct msm_priv,
idle_source);
struct msm_priv *priv = the_msm_priv;
switch (event) {
case MSM_DCVS_ENABLE_IDLE_PULSE:
@ -53,12 +53,10 @@ static int msm_idle_enable(struct msm_dcvs_idle *self,
/* Set the requested frequency if it is within 5MHz (delta) of a
* supported frequency.
*/
static int msm_set_freq(struct msm_dcvs_freq *self,
unsigned int freq)
static int msm_set_freq(int core_num, unsigned int freq)
{
int i, delta = 5000000;
struct msm_priv *priv = container_of(self, struct msm_priv,
freq_sink);
struct msm_priv *priv = the_msm_priv;
struct kgsl_device *device = priv->device;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
@ -79,10 +77,10 @@ static int msm_set_freq(struct msm_dcvs_freq *self,
return priv->cur_freq / 1000;
}
static unsigned int msm_get_freq(struct msm_dcvs_freq *self)
static unsigned int msm_get_freq(int core_num)
{
struct msm_priv *priv = container_of(self, struct msm_priv,
freq_sink);
struct msm_priv *priv = the_msm_priv;
/* return current frequency in kHz */
return priv->cur_freq / 1000;
}
@ -92,7 +90,7 @@ static void msm_busy(struct kgsl_device *device,
{
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && !priv->gpu_busy) {
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_EXIT, 0);
trace_kgsl_mpdcvs(device, 1);
priv->gpu_busy = 1;
}
@ -106,7 +104,8 @@ static void msm_idle(struct kgsl_device *device,
if (priv->enabled && priv->gpu_busy)
if (device->ftbl->isidle(device)) {
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
msm_dcvs_idle(priv->dcvs_core_id,
MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@ -119,7 +118,7 @@ static void msm_sleep(struct kgsl_device *device,
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && priv->gpu_busy) {
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@ -132,7 +131,7 @@ static int msm_init(struct kgsl_device *device,
{
struct msm_priv *priv;
struct msm_dcvs_freq_entry *tbl;
int i, ret, low_level;
int i, ret = -EINVAL, low_level;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
@ -149,29 +148,24 @@ static int msm_init(struct kgsl_device *device,
low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
for (i = 0; i <= low_level; i++)
tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
ret = msm_dcvs_register_core(device->name, priv->core_info,
priv->dcvs_core_id = msm_dcvs_register_core(MSM_DCVS_CORE_TYPE_GPU, 0,
priv->core_info,
msm_set_freq, msm_get_freq, msm_idle_enable,
priv->core_info->sensors[0]);
if (ret) {
if (priv->dcvs_core_id < 0) {
KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
goto err;
}
priv->device = device;
priv->idle_source.core_name = device->name;
priv->handle = msm_dcvs_idle_source_register(&priv->idle_source);
if (priv->handle < 0) {
ret = priv->handle;
KGSL_PWR_ERR(device, "msm_dcvs_idle_source_register failed\n");
goto err;
}
priv->freq_sink.core_name = device->name;
ret = msm_dcvs_freq_sink_start(&priv->freq_sink);
the_msm_priv = priv;
ret = msm_dcvs_freq_sink_start(priv->dcvs_core_id);
if (ret >= 0) {
if (device->ftbl->isidle(device)) {
priv->gpu_busy = 0;
msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
msm_dcvs_idle(priv->dcvs_core_id,
MSM_DCVS_IDLE_ENTER, 0);
} else {
priv->gpu_busy = 1;
}
@ -179,7 +173,6 @@ static int msm_init(struct kgsl_device *device,
}
KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
msm_dcvs_idle_source_unregister(&priv->idle_source);
err:
kfree(pwrscale->priv);
@ -195,8 +188,7 @@ static void msm_close(struct kgsl_device *device,
if (pwrscale->priv == NULL)
return;
msm_dcvs_idle_source_unregister(&priv->idle_source);
msm_dcvs_freq_sink_stop(&priv->freq_sink);
msm_dcvs_freq_sink_stop(priv->dcvs_core_id);
kfree(pwrscale->priv);
pwrscale->priv = NULL;
}