123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- /* Copyright (c) 2012, 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #define pr_fmt(fmt) "mpd %s: " fmt, __func__
- #include <linux/cpumask.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/mutex.h>
- #include <linux/kthread.h>
- #include <linux/kobject.h>
- #include <linux/ktime.h>
- #include <linux/hrtimer.h>
- #include <linux/slab.h>
- #include <linux/spinlock.h>
- #include <linux/cpu.h>
- #include <linux/stringify.h>
- #include <linux/sched.h>
- #include <linux/platform_device.h>
- #include <linux/debugfs.h>
- #include <linux/cpu_pm.h>
- #include <linux/cpu.h>
- #include <linux/cpufreq.h>
- #include <linux/sched.h>
- #include <linux/rq_stats.h>
- #include <asm/atomic.h>
- #include <asm/page.h>
- #include <mach/msm_dcvs.h>
- #include <mach/msm_dcvs_scm.h>
- #define CREATE_TRACE_POINTS
- #include <trace/events/mpdcvs_trace.h>
- #define DEFAULT_RQ_AVG_POLL_MS (1)
- #define DEFAULT_RQ_AVG_DIVIDE (25)
- struct mpd_attrib {
- struct kobj_attribute enabled;
- struct kobj_attribute rq_avg_poll_ms;
- struct kobj_attribute iowait_threshold_pct;
- struct kobj_attribute rq_avg_divide;
- struct kobj_attribute em_win_size_min_us;
- struct kobj_attribute em_win_size_max_us;
- struct kobj_attribute em_max_util_pct;
- struct kobj_attribute mp_em_rounding_point_min;
- struct kobj_attribute mp_em_rounding_point_max;
- struct kobj_attribute online_util_pct_min;
- struct kobj_attribute online_util_pct_max;
- struct kobj_attribute slack_time_min_us;
- struct kobj_attribute slack_time_max_us;
- struct kobj_attribute hp_up_max_ms;
- struct kobj_attribute hp_up_ms;
- struct kobj_attribute hp_up_count;
- struct kobj_attribute hp_dw_max_ms;
- struct kobj_attribute hp_dw_ms;
- struct kobj_attribute hp_dw_count;
- struct attribute_group attrib_group;
- };
- struct msm_mpd_scm_data {
- enum msm_dcvs_scm_event event;
- int nr;
- };
- struct mpdecision {
- uint32_t enabled;
- atomic_t algo_cpu_mask;
- uint32_t rq_avg_poll_ms;
- uint32_t iowait_threshold_pct;
- uint32_t rq_avg_divide;
- ktime_t next_update;
- uint32_t slack_us;
- struct msm_mpd_algo_param mp_param;
- struct mpd_attrib attrib;
- struct mutex lock;
- struct task_struct *task;
- struct task_struct *hptask;
- struct hrtimer slack_timer;
- struct msm_mpd_scm_data data;
- int hpupdate;
- wait_queue_head_t wait_q;
- wait_queue_head_t wait_hpq;
- };
- struct hp_latency {
- int hp_up_max_ms;
- int hp_up_ms;
- int hp_up_count;
- int hp_dw_max_ms;
- int hp_dw_ms;
- int hp_dw_count;
- };
- static DEFINE_PER_CPU(struct hrtimer, rq_avg_poll_timer);
- static DEFINE_SPINLOCK(rq_avg_lock);
- enum {
- MSM_MPD_DEBUG_NOTIFIER = BIT(0),
- MSM_MPD_CORE_STATUS = BIT(1),
- MSM_MPD_SLACK_TIMER = BIT(2),
- };
- enum {
- HPUPDATE_WAITING = 0, /* we are waiting for cpumask update */
- HPUPDATE_SCHEDULED = 1, /* we are in the process of hotplugging */
- HPUPDATE_IN_PROGRESS = 2, /* we are in the process of hotplugging */
- };
- static int msm_mpd_enabled = 1;
- module_param_named(enabled, msm_mpd_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
- static struct dentry *debugfs_base;
- static struct mpdecision msm_mpd;
- static struct hp_latency hp_latencies;
- static unsigned long last_nr;
- static int num_present_hundreds;
- static ktime_t last_down_time;
- static bool ok_to_update_tz(int nr, int last_nr)
- {
- /*
- * Exclude unnecessary TZ reports if run queue haven't changed much from
- * the last reported value. The divison by rq_avg_divide is to
- * filter out small changes in the run queue average which won't cause
- * a online cpu mask change. Also if the cpu online count does not match
- * the count requested by TZ and we are not in the process of bringing
- * cpus online as indicated by a HPUPDATE_IN_PROGRESS in msm_mpd.hpdata
- */
- return
- (((nr / msm_mpd.rq_avg_divide)
- != (last_nr / msm_mpd.rq_avg_divide))
- || ((hweight32(atomic_read(&msm_mpd.algo_cpu_mask))
- != num_online_cpus())
- && (msm_mpd.hpupdate != HPUPDATE_IN_PROGRESS)));
- }
- static enum hrtimer_restart msm_mpd_rq_avg_poll_timer(struct hrtimer *timer)
- {
- int nr, nr_iowait;
- ktime_t curr_time = ktime_get();
- unsigned long flags;
- int cpu = smp_processor_id();
- enum hrtimer_restart restart = HRTIMER_RESTART;
- spin_lock_irqsave(&rq_avg_lock, flags);
- /* If running on the wrong cpu, don't restart */
- if (&per_cpu(rq_avg_poll_timer, cpu) != timer)
- restart = HRTIMER_NORESTART;
- if (ktime_to_ns(ktime_sub(curr_time, msm_mpd.next_update)) < 0)
- goto out;
- msm_mpd.next_update = ktime_add_ns(curr_time,
- (msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
- sched_get_nr_running_avg(&nr, &nr_iowait);
- if ((nr_iowait >= msm_mpd.iowait_threshold_pct) && (nr < last_nr))
- nr = last_nr;
- if (nr > num_present_hundreds)
- nr = num_present_hundreds;
- trace_msm_mp_runq("nr_running", nr);
- if (ok_to_update_tz(nr, last_nr)) {
- hrtimer_try_to_cancel(&msm_mpd.slack_timer);
- msm_mpd.data.nr = nr;
- msm_mpd.data.event = MSM_DCVS_SCM_RUNQ_UPDATE;
- wake_up(&msm_mpd.wait_q);
- last_nr = nr;
- }
- out:
- hrtimer_set_expires(timer, msm_mpd.next_update);
- spin_unlock_irqrestore(&rq_avg_lock, flags);
- /* set next expiration */
- return restart;
- }
- static void bring_up_cpu(int cpu)
- {
- int cpu_action_time_ms;
- int time_taken_ms;
- int ret, ret1, ret2;
- cpu_action_time_ms = ktime_to_ms(ktime_get());
- ret = cpu_up(cpu);
- if (ret) {
- pr_debug("Error %d online core %d\n", ret, cpu);
- } else {
- time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
- if (time_taken_ms > hp_latencies.hp_up_max_ms)
- hp_latencies.hp_up_max_ms = time_taken_ms;
- hp_latencies.hp_up_ms += time_taken_ms;
- hp_latencies.hp_up_count++;
- ret = msm_dcvs_scm_event(
- CPU_OFFSET + cpu,
- MSM_DCVS_SCM_CORE_ONLINE,
- cpufreq_get(cpu),
- (uint32_t) time_taken_ms * USEC_PER_MSEC,
- &ret1, &ret2);
- if (ret)
- pr_err("Error sending hotplug scm event err=%d\n", ret);
- }
- }
- static void bring_down_cpu(int cpu)
- {
- int cpu_action_time_ms;
- int time_taken_ms;
- int ret, ret1, ret2;
- BUG_ON(cpu == 0);
- cpu_action_time_ms = ktime_to_ms(ktime_get());
- ret = cpu_down(cpu);
- if (ret) {
- pr_debug("Error %d offline" "core %d\n", ret, cpu);
- } else {
- time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
- if (time_taken_ms > hp_latencies.hp_dw_max_ms)
- hp_latencies.hp_dw_max_ms = time_taken_ms;
- hp_latencies.hp_dw_ms += time_taken_ms;
- hp_latencies.hp_dw_count++;
- ret = msm_dcvs_scm_event(
- CPU_OFFSET + cpu,
- MSM_DCVS_SCM_CORE_OFFLINE,
- (uint32_t) time_taken_ms * USEC_PER_MSEC,
- 0,
- &ret1, &ret2);
- if (ret)
- pr_err("Error sending hotplug scm event err=%d\n", ret);
- }
- }
- static int __ref msm_mpd_update_scm(enum msm_dcvs_scm_event event, int nr)
- {
- int ret = 0;
- uint32_t req_cpu_mask = 0;
- uint32_t slack_us = 0;
- uint32_t param0 = 0;
- if (event == MSM_DCVS_SCM_RUNQ_UPDATE)
- param0 = nr;
- ret = msm_dcvs_scm_event(0, event, param0, 0,
- &req_cpu_mask, &slack_us);
- if (ret) {
- pr_err("Error (%d) sending event %d, param %d\n", ret, event,
- param0);
- return ret;
- }
- trace_msm_mp_cpusonline("cpu_online_mp", req_cpu_mask);
- trace_msm_mp_slacktime("slack_time_mp", slack_us);
- msm_mpd.slack_us = slack_us;
- atomic_set(&msm_mpd.algo_cpu_mask, req_cpu_mask);
- msm_mpd.hpupdate = HPUPDATE_SCHEDULED;
- wake_up(&msm_mpd.wait_hpq);
- /* Start MP Decision slack timer */
- if (slack_us) {
- hrtimer_cancel(&msm_mpd.slack_timer);
- ret = hrtimer_start(&msm_mpd.slack_timer,
- ktime_set(0, slack_us * NSEC_PER_USEC),
- HRTIMER_MODE_REL_PINNED);
- if (ret)
- pr_err("Failed to register slack timer (%d) %d\n",
- slack_us, ret);
- }
- return ret;
- }
- static enum hrtimer_restart msm_mpd_slack_timer(struct hrtimer *timer)
- {
- unsigned long flags;
- trace_printk("mpd:slack_timer_fired!\n");
- spin_lock_irqsave(&rq_avg_lock, flags);
- if (msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE)
- goto out;
- msm_mpd.data.nr = 0;
- msm_mpd.data.event = MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED;
- wake_up(&msm_mpd.wait_q);
- out:
- spin_unlock_irqrestore(&rq_avg_lock, flags);
- return HRTIMER_NORESTART;
- }
- static int msm_mpd_idle_notifier(struct notifier_block *self,
- unsigned long cmd, void *v)
- {
- int cpu = smp_processor_id();
- unsigned long flags;
- switch (cmd) {
- case CPU_PM_EXIT:
- spin_lock_irqsave(&rq_avg_lock, flags);
- hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
- msm_mpd.next_update,
- HRTIMER_MODE_ABS_PINNED);
- spin_unlock_irqrestore(&rq_avg_lock, flags);
- break;
- case CPU_PM_ENTER:
- hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
- break;
- default:
- break;
- }
- return NOTIFY_OK;
- }
- static int msm_mpd_hotplug_notifier(struct notifier_block *self,
- unsigned long action, void *hcpu)
- {
- int cpu = (int)hcpu;
- unsigned long flags;
- switch (action & (~CPU_TASKS_FROZEN)) {
- case CPU_STARTING:
- spin_lock_irqsave(&rq_avg_lock, flags);
- hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
- msm_mpd.next_update,
- HRTIMER_MODE_ABS_PINNED);
- spin_unlock_irqrestore(&rq_avg_lock, flags);
- break;
- default:
- break;
- }
- return NOTIFY_OK;
- }
- static struct notifier_block msm_mpd_idle_nb = {
- .notifier_call = msm_mpd_idle_notifier,
- };
- static struct notifier_block msm_mpd_hotplug_nb = {
- .notifier_call = msm_mpd_hotplug_notifier,
- };
- static int __cpuinit msm_mpd_do_hotplug(void *data)
- {
- int *event = (int *)data;
- int cpu;
- while (1) {
- msm_dcvs_update_algo_params();
- wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
- if (kthread_should_stop())
- break;
- msm_mpd.hpupdate = HPUPDATE_IN_PROGRESS;
- /*
- * Bring online any offline cores, then offline any online
- * cores. Whenever a core is off/onlined restart the procedure
- * in case a new core is desired to be brought online in the
- * mean time.
- */
- restart:
- for_each_possible_cpu(cpu) {
- if ((atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
- && !cpu_online(cpu)) {
- bring_up_cpu(cpu);
- if (cpu_online(cpu))
- goto restart;
- }
- }
- if (ktime_to_ns(ktime_sub(ktime_get(), last_down_time)) >
- 100 * NSEC_PER_MSEC)
- for_each_possible_cpu(cpu)
- if (!(atomic_read(&msm_mpd.algo_cpu_mask) &
- (1 << cpu)) && cpu_online(cpu)) {
- bring_down_cpu(cpu);
- last_down_time = ktime_get();
- break;
- }
- msm_mpd.hpupdate = HPUPDATE_WAITING;
- msm_dcvs_apply_gpu_floor(0);
- }
- return 0;
- }
- static int msm_mpd_do_update_scm(void *data)
- {
- struct msm_mpd_scm_data *scm_data = (struct msm_mpd_scm_data *)data;
- unsigned long flags;
- enum msm_dcvs_scm_event event;
- int nr;
- while (1) {
- wait_event(msm_mpd.wait_q,
- msm_mpd.data.event == MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
- || msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE
- || kthread_should_stop());
- if (kthread_should_stop())
- break;
- spin_lock_irqsave(&rq_avg_lock, flags);
- event = scm_data->event;
- nr = scm_data->nr;
- scm_data->event = 0;
- scm_data->nr = 0;
- spin_unlock_irqrestore(&rq_avg_lock, flags);
- msm_mpd_update_scm(event, nr);
- }
- return 0;
- }
- static int __ref msm_mpd_set_enabled(uint32_t enable)
- {
- int ret = 0;
- int ret0 = 0;
- int ret1 = 0;
- int cpu;
- static uint32_t last_enable;
- enable = (enable > 0) ? 1 : 0;
- if (last_enable == enable)
- return ret;
- if (enable) {
- ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param);
- if (ret) {
- pr_err("Error(%d): msm_mpd_scm_set_algo_params failed\n",
- ret);
- return ret;
- }
- }
- ret = msm_dcvs_scm_event(0, MSM_DCVS_SCM_MPD_ENABLE, enable, 0,
- &ret0, &ret1);
- if (ret) {
- pr_err("Error(%d) %s MP Decision\n",
- ret, (enable ? "enabling" : "disabling"));
- } else {
- last_enable = enable;
- last_nr = 0;
- }
- if (enable) {
- msm_mpd.next_update = ktime_add_ns(ktime_get(),
- (msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
- msm_mpd.task = kthread_run(msm_mpd_do_update_scm,
- &msm_mpd.data, "msm_mpdecision");
- if (IS_ERR(msm_mpd.task))
- return -EFAULT;
- msm_mpd.hptask = kthread_run(msm_mpd_do_hotplug,
- &msm_mpd.hpupdate, "msm_hp");
- if (IS_ERR(msm_mpd.hptask))
- return -EFAULT;
- for_each_online_cpu(cpu)
- hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
- msm_mpd.next_update,
- HRTIMER_MODE_ABS_PINNED);
- cpu_pm_register_notifier(&msm_mpd_idle_nb);
- register_cpu_notifier(&msm_mpd_hotplug_nb);
- msm_mpd.enabled = 1;
- } else {
- for_each_online_cpu(cpu)
- hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
- kthread_stop(msm_mpd.hptask);
- kthread_stop(msm_mpd.task);
- cpu_pm_unregister_notifier(&msm_mpd_idle_nb);
- unregister_cpu_notifier(&msm_mpd_hotplug_nb);
- msm_mpd.enabled = 0;
- }
- return ret;
- }
- static int msm_mpd_set_rq_avg_poll_ms(uint32_t val)
- {
- /*
- * No need to do anything. Just let the timer set its own next poll
- * interval when it next fires.
- */
- msm_mpd.rq_avg_poll_ms = val;
- return 0;
- }
- static int msm_mpd_set_iowait_threshold_pct(uint32_t val)
- {
- /*
- * No need to do anything. Just let the timer set its own next poll
- * interval when it next fires.
- */
- msm_mpd.iowait_threshold_pct = val;
- return 0;
- }
- static int msm_mpd_set_rq_avg_divide(uint32_t val)
- {
- /*
- * No need to do anything. New value will be used next time
- * the decision is made as to whether to update tz.
- */
- if (val == 0)
- return -EINVAL;
- msm_mpd.rq_avg_divide = val;
- return 0;
- }
- #define MPD_ALGO_PARAM(_name, _param) \
- static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
- } \
- static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
- struct kobj_attribute *attr, const char *buf, size_t count) \
- { \
- int ret = 0; \
- uint32_t val; \
- uint32_t old_val; \
- mutex_lock(&msm_mpd.lock); \
- ret = kstrtouint(buf, 10, &val); \
- if (ret) { \
- pr_err("Invalid input %s for %s %d\n", \
- buf, __stringify(_name), ret);\
- return 0; \
- } \
- old_val = _param; \
- _param = val; \
- ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param); \
- if (ret) { \
- pr_err("Error %d returned when setting algo param %s to %d\n",\
- ret, __stringify(_name), val); \
- _param = old_val; \
- } \
- mutex_unlock(&msm_mpd.lock); \
- return count; \
- }
- #define MPD_PARAM(_name, _param) \
- static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
- } \
- static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
- struct kobj_attribute *attr, const char *buf, size_t count) \
- { \
- int ret = 0; \
- uint32_t val; \
- uint32_t old_val; \
- mutex_lock(&msm_mpd.lock); \
- ret = kstrtouint(buf, 10, &val); \
- if (ret) { \
- pr_err("Invalid input %s for %s %d\n", \
- buf, __stringify(_name), ret);\
- return 0; \
- } \
- old_val = _param; \
- ret = msm_mpd_set_##_name(val); \
- if (ret) { \
- pr_err("Error %d returned when setting algo param %s to %d\n",\
- ret, __stringify(_name), val); \
- _param = old_val; \
- } \
- mutex_unlock(&msm_mpd.lock); \
- return count; \
- }
- #define MPD_RW_ATTRIB(i, _name) \
- msm_mpd.attrib._name.attr.name = __stringify(_name); \
- msm_mpd.attrib._name.attr.mode = S_IRUGO | S_IWUSR; \
- msm_mpd.attrib._name.show = msm_mpd_attr_##_name##_show; \
- msm_mpd.attrib._name.store = msm_mpd_attr_##_name##_store; \
- msm_mpd.attrib.attrib_group.attrs[i] = &msm_mpd.attrib._name.attr;
- MPD_PARAM(enabled, msm_mpd.enabled);
- MPD_PARAM(rq_avg_poll_ms, msm_mpd.rq_avg_poll_ms);
- MPD_PARAM(iowait_threshold_pct, msm_mpd.iowait_threshold_pct);
- MPD_PARAM(rq_avg_divide, msm_mpd.rq_avg_divide);
- MPD_ALGO_PARAM(em_win_size_min_us, msm_mpd.mp_param.em_win_size_min_us);
- MPD_ALGO_PARAM(em_win_size_max_us, msm_mpd.mp_param.em_win_size_max_us);
- MPD_ALGO_PARAM(em_max_util_pct, msm_mpd.mp_param.em_max_util_pct);
- MPD_ALGO_PARAM(mp_em_rounding_point_min,
- msm_mpd.mp_param.mp_em_rounding_point_min);
- MPD_ALGO_PARAM(mp_em_rounding_point_max,
- msm_mpd.mp_param.mp_em_rounding_point_max);
- MPD_ALGO_PARAM(online_util_pct_min, msm_mpd.mp_param.online_util_pct_min);
- MPD_ALGO_PARAM(online_util_pct_max, msm_mpd.mp_param.online_util_pct_max);
- MPD_ALGO_PARAM(slack_time_min_us, msm_mpd.mp_param.slack_time_min_us);
- MPD_ALGO_PARAM(slack_time_max_us, msm_mpd.mp_param.slack_time_max_us);
- MPD_ALGO_PARAM(hp_up_max_ms, hp_latencies.hp_up_max_ms);
- MPD_ALGO_PARAM(hp_up_ms, hp_latencies.hp_up_ms);
- MPD_ALGO_PARAM(hp_up_count, hp_latencies.hp_up_count);
- MPD_ALGO_PARAM(hp_dw_max_ms, hp_latencies.hp_dw_max_ms);
- MPD_ALGO_PARAM(hp_dw_ms, hp_latencies.hp_dw_ms);
- MPD_ALGO_PARAM(hp_dw_count, hp_latencies.hp_dw_count);
- static int __devinit msm_mpd_probe(struct platform_device *pdev)
- {
- struct kobject *module_kobj = NULL;
- int ret = 0;
- const int attr_count = 20;
- struct msm_mpd_algo_param *param = NULL;
- param = pdev->dev.platform_data;
- module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
- if (!module_kobj) {
- pr_err("Cannot find kobject for module %s\n", KBUILD_MODNAME);
- ret = -ENOENT;
- goto done;
- }
- msm_mpd.attrib.attrib_group.attrs =
- kzalloc(attr_count * sizeof(struct attribute *), GFP_KERNEL);
- if (!msm_mpd.attrib.attrib_group.attrs) {
- ret = -ENOMEM;
- goto done;
- }
- MPD_RW_ATTRIB(0, enabled);
- MPD_RW_ATTRIB(1, rq_avg_poll_ms);
- MPD_RW_ATTRIB(2, iowait_threshold_pct);
- MPD_RW_ATTRIB(3, rq_avg_divide);
- MPD_RW_ATTRIB(4, em_win_size_min_us);
- MPD_RW_ATTRIB(5, em_win_size_max_us);
- MPD_RW_ATTRIB(6, em_max_util_pct);
- MPD_RW_ATTRIB(7, mp_em_rounding_point_min);
- MPD_RW_ATTRIB(8, mp_em_rounding_point_max);
- MPD_RW_ATTRIB(9, online_util_pct_min);
- MPD_RW_ATTRIB(10, online_util_pct_max);
- MPD_RW_ATTRIB(11, slack_time_min_us);
- MPD_RW_ATTRIB(12, slack_time_max_us);
- MPD_RW_ATTRIB(13, hp_up_max_ms);
- MPD_RW_ATTRIB(14, hp_up_ms);
- MPD_RW_ATTRIB(15, hp_up_count);
- MPD_RW_ATTRIB(16, hp_dw_max_ms);
- MPD_RW_ATTRIB(17, hp_dw_ms);
- MPD_RW_ATTRIB(18, hp_dw_count);
- msm_mpd.attrib.attrib_group.attrs[19] = NULL;
- ret = sysfs_create_group(module_kobj, &msm_mpd.attrib.attrib_group);
- if (ret)
- pr_err("Unable to create sysfs objects :%d\n", ret);
- msm_mpd.rq_avg_poll_ms = DEFAULT_RQ_AVG_POLL_MS;
- msm_mpd.rq_avg_divide = DEFAULT_RQ_AVG_DIVIDE;
- memcpy(&msm_mpd.mp_param, param, sizeof(struct msm_mpd_algo_param));
- debugfs_base = debugfs_create_dir("msm_mpdecision", NULL);
- if (!debugfs_base) {
- pr_err("Cannot create debugfs base msm_mpdecision\n");
- ret = -ENOENT;
- goto done;
- }
- done:
- if (ret && debugfs_base)
- debugfs_remove(debugfs_base);
- return ret;
- }
- static int __devexit msm_mpd_remove(struct platform_device *pdev)
- {
- platform_set_drvdata(pdev, NULL);
- return 0;
- }
- static struct platform_driver msm_mpd_driver = {
- .probe = msm_mpd_probe,
- .remove = __devexit_p(msm_mpd_remove),
- .driver = {
- .name = "msm_mpdecision",
- .owner = THIS_MODULE,
- },
- };
- static int __init msm_mpdecision_init(void)
- {
- int cpu;
- if (!msm_mpd_enabled) {
- pr_info("Not enabled\n");
- return 0;
- }
- num_present_hundreds = 100 * num_present_cpus();
- hrtimer_init(&msm_mpd.slack_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL_PINNED);
- msm_mpd.slack_timer.function = msm_mpd_slack_timer;
- for_each_possible_cpu(cpu) {
- hrtimer_init(&per_cpu(rq_avg_poll_timer, cpu),
- CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
- per_cpu(rq_avg_poll_timer, cpu).function
- = msm_mpd_rq_avg_poll_timer;
- }
- mutex_init(&msm_mpd.lock);
- init_waitqueue_head(&msm_mpd.wait_q);
- init_waitqueue_head(&msm_mpd.wait_hpq);
- return platform_driver_register(&msm_mpd_driver);
- }
- late_initcall(msm_mpdecision_init);
|