#include <linux/profile.h>
#include <linux/sched.h>
#include <linux/module.h>
+#ifdef CONFIG_MTK_SCHED_RQAVG_US
+#include <linux/rq_stats.h>
+#endif
#include <linux/irq_work.h>
#include <linux/posix-timers.h>
#include <linux/perf_event.h>
#include <trace/events/timer.h>
+#ifdef CONFIG_MTK_SCHED_RQAVG_US
+struct rq_data rq_info;
+#ifdef CONFIG_MTK_SCHED_RQAVG_US_ENABLE_WQ
+struct workqueue_struct *rq_wq;
+#endif
+spinlock_t rq_lock;
+#endif
+
+#ifdef CONFIG_MT_LOAD_BALANCE_PROFILER
+#include <mtlbprof/mtlbprof.h>
+#endif
+
/*
* Per cpu nohz control structure
*/
* we can't safely shutdown that CPU.
*/
if (have_nohz_full_mask && tick_do_timer_cpu == cpu)
- return -EINVAL;
+ return NOTIFY_BAD;
break;
}
return NOTIFY_OK;
update_ts_time_stats(cpu, ts, now, NULL);
ts->idle_active = 0;
+#ifdef CONFIG_MT_LOAD_BALANCE_PROFILER
+ mt_lbprof_update_state(cpu, MT_LBPROF_NO_TASK_STATE);
+#endif
sched_clock_idle_wakeup_event(0);
}
ts->idle_entrytime = now;
ts->idle_active = 1;
+#ifdef CONFIG_MT_LOAD_BALANCE_PROFILER
+ mt_lbprof_update_state(cpu, MT_LBPROF_NO_TASK_STATE);
+#endif
+
sched_clock_idle_sleep_event();
return now;
}
return false;
}
- if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
+ if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) {
+ ts->sleep_length = (ktime_t) { .tv64 = NSEC_PER_SEC/HZ };
return false;
+ }
if (need_resched())
return false;
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
- if (ts->inidle) {
- /* Cancel the timer because CPU already waken up from the C-states*/
- menu_hrtimer_cancel();
+ if (ts->inidle)
__tick_nohz_idle_enter(ts);
- } else {
+ else
tick_nohz_full_stop_tick(ts);
- }
}
/**
ts->inidle = 0;
- /* Cancel the timer because CPU already waken up from the C-states*/
- menu_hrtimer_cancel();
if (ts->idle_active || ts->tick_stopped)
now = ktime_get();
* High resolution timer specific code
*/
#ifdef CONFIG_HIGH_RES_TIMERS
+
+#ifdef CONFIG_MTK_SCHED_RQAVG_US
+static void update_rq_stats(void)
+{
+ unsigned long jiffy_gap = 0;
+ unsigned int rq_avg = 0;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&rq_lock, flags);
+
+ jiffy_gap = jiffies - rq_info.rq_poll_last_jiffy;
+ if (jiffy_gap >= rq_info.rq_poll_jiffies) {
+ if (!rq_info.rq_avg)
+ rq_info.rq_poll_total_jiffies = 0;
+
+ rq_avg = nr_running() * 10;
+
+ if (rq_info.rq_poll_total_jiffies) {
+ rq_avg = (rq_avg * jiffy_gap) +
+ (rq_info.rq_avg *
+ rq_info.rq_poll_total_jiffies);
+ do_div(rq_avg,
+ rq_info.rq_poll_total_jiffies + jiffy_gap);
+ }
+
+ rq_info.rq_avg = rq_avg;
+ rq_info.rq_poll_total_jiffies += jiffy_gap;
+ rq_info.rq_poll_last_jiffy = jiffies;
+ }
+
+ spin_unlock_irqrestore(&rq_lock, flags);
+}
+
+#ifdef CONFIG_MTK_SCHED_RQAVG_US_ENABLE_WQ
+static void wakeup_user(void)
+{
+ unsigned long jiffy_gap;
+
+ jiffy_gap = jiffies - rq_info.def_timer_last_jiffy;
+
+ if (jiffy_gap >= rq_info.def_timer_jiffies) {
+ rq_info.def_timer_last_jiffy = jiffies;
+ queue_work(rq_wq, &rq_info.def_timer_work);
+ }
+}
+#endif /* CONFIG_MTK_SCHED_RQAVG_US_ENABLE_WQ */
+
+#endif /* CONFIG_MTK_SCHED_RQAVG_US */
/*
* We rearm the timer until we get disabled by the idle code.
* Called with interrupts disabled.
if (regs)
tick_sched_handle(ts, regs);
+#ifdef CONFIG_MTK_SCHED_RQAVG_US
+ if ((rq_info.init == 1) && (tick_do_timer_cpu == smp_processor_id())) {
+
+ /*
+ * update run queue statistics
+ */
+ update_rq_stats();
+
+#ifdef CONFIG_MTK_SCHED_RQAVG_US_ENABLE_WQ
+ /*
+ * wakeup user if needed
+ */
+ wakeup_user();
+#endif /* CONFIG_MTK_SCHED_RQAVG_US_ENABLE_WQ */
+ }
+#endif /* CONFIG_MTK_SCHED_RQAVG_US */
+
hrtimer_forward(timer, now, tick_period);
return HRTIMER_RESTART;
hrtimer_cancel(&ts->sched_timer);
# endif
- memset(ts, 0, sizeof(*ts));
+ //memset(ts, 0, sizeof(*ts)); /*to avoid idle time clear to 0 after CPU plug off*/
+ ts->nohz_mode = NOHZ_MODE_INACTIVE;
}
#endif