mirror of https://github.com/OpenIPC/firmware.git
119 lines
3.7 KiB
Diff
119 lines
3.7 KiB
Diff
diff -drupN a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
|
|
--- a/drivers/cpuidle/cpuidle.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/drivers/cpuidle/cpuidle.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -160,6 +160,60 @@ int cpuidle_enter_freeze(struct cpuidle_
|
|
}
|
|
#endif /* CONFIG_SUSPEND */
|
|
|
|
+#ifdef CONFIG_ARM_SUNXI_CPUIDLE_TIMESTAMP
|
|
+static inline u64 arch_counter_get_cntpct(void)
|
|
+{
|
|
+ u64 cval;
|
|
+
|
|
+ isb();
|
|
+ asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
|
|
+ return cval;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 0xc0020800~0xc0021000 is reserved in dts,
|
|
+ * just follow standby space.
|
|
+ * this space is used to record the timestamps
|
|
+ * of each stage in cpuidle. each cpu occupy
|
|
+ * 48 bytes.
|
|
+ */
|
|
+#define CPUIDLE_TIMESTAMPS_BASE (phys_to_virt((const volatile void *)0x40020800))
|
|
+#define DIV24(x) (((x) * 85) >> 11)
|
|
+
|
|
+typedef struct cpuidle_timestamps {
|
|
+ /* Linux record when cpuidle enter */
|
|
+ u64 cpux_idle_enter_time;
|
|
+ /* optee record before wfi */
|
|
+ u64 cpux_idle_finish_time;
|
|
+ /* cpus record when core down */
|
|
+ u64 cpux_core_down_time;
|
|
+ /* cpus record when gicout */
|
|
+ u64 cpus_wake_up_time;
|
|
+ /* optee record when core up */
|
|
+ u64 cpux_start_wake_time;
|
|
+ /* Linux record when cpuidle exit */
|
|
+ u64 cpux_wakeup_finish_time;
|
|
+} cpuidle_timestamps_t;
|
|
+
|
|
+#define software_core_close_time(cpu) \
|
|
+ (cpuidle_time[cpu].cpux_idle_finish_time -\
|
|
+ cpuidle_time[cpu].cpux_idle_enter_time)
|
|
+#define hardware_core_close_time(cpu) \
|
|
+ (cpuidle_time[cpu].cpux_core_down_time -\
|
|
+ cpuidle_time[cpu].cpux_idle_finish_time)
|
|
+
|
|
+#define software_core_open_time(cpu) \
|
|
+ (cpuidle_time[cpu].cpux_wakeup_finish_time -\
|
|
+ cpuidle_time[cpu].cpux_start_wake_time)
|
|
+#define hardware_core_open_time(cpu) \
|
|
+ (cpuidle_time[cpu].cpux_start_wake_time -\
|
|
+ cpuidle_time[cpu].cpus_wake_up_time)
|
|
+
|
|
+#define resident_core_down_time(cpu) \
|
|
+ (cpuidle_time[cpu].cpux_wakeup_finish_time -\
|
|
+ cpuidle_time[cpu].cpux_idle_enter_time)
|
|
+
|
|
+#endif
|
|
/**
|
|
* cpuidle_enter_state - enter the state and update stats
|
|
* @dev: cpuidle device for this cpu
|
|
@@ -175,7 +229,11 @@ int cpuidle_enter_state(struct cpuidle_d
|
|
bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
|
|
ktime_t time_start, time_end;
|
|
s64 diff;
|
|
-
|
|
+#ifdef CONFIG_ARM_SUNXI_CPUIDLE_TIMESTAMP
|
|
+ int cpu = smp_processor_id();
|
|
+ cpuidle_timestamps_t *cpuidle_time =
|
|
+ (cpuidle_timestamps_t *)CPUIDLE_TIMESTAMPS_BASE;
|
|
+#endif
|
|
/*
|
|
* Tell the time framework to switch to a broadcast timer because our
|
|
* local timer will be shut down. If a local timer is used from another
|
|
@@ -193,20 +251,37 @@ int cpuidle_enter_state(struct cpuidle_d
|
|
}
|
|
|
|
/* Take note of the planned idle state. */
|
|
- sched_idle_set_state(target_state);
|
|
+ sched_idle_set_state(target_state, index);
|
|
|
|
trace_cpu_idle_rcuidle(index, dev->cpu);
|
|
time_start = ns_to_ktime(local_clock());
|
|
-
|
|
stop_critical_timings();
|
|
+
|
|
+#ifdef CONFIG_ARM_SUNXI_CPUIDLE_TIMESTAMP
|
|
+ if ((index > 0) && (cpu != 0))
|
|
+ cpuidle_time[cpu].cpux_idle_enter_time =
|
|
+ arch_counter_get_cntpct();
|
|
+#endif
|
|
entered_state = target_state->enter(dev, drv, index);
|
|
+#ifdef CONFIG_ARM_SUNXI_CPUIDLE_TIMESTAMP
|
|
+ if ((index > 0) && (cpu != 0) && (cpu == smp_processor_id())) {
|
|
+ cpuidle_time[cpu].cpux_wakeup_finish_time =
|
|
+ arch_counter_get_cntpct();
|
|
+ pr_err("c%d, es:%lld, eh:%lld, xh:%lld, xs:%lld, r:%lld\n", cpu,
|
|
+ DIV24(software_core_close_time(cpu)),
|
|
+ DIV24(hardware_core_close_time(cpu)),
|
|
+ DIV24(hardware_core_open_time(cpu)),
|
|
+ DIV24(software_core_open_time(cpu)),
|
|
+ DIV24(resident_core_down_time(cpu)));
|
|
+ }
|
|
+#endif
|
|
start_critical_timings();
|
|
|
|
time_end = ns_to_ktime(local_clock());
|
|
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
|
|
|
|
/* The cpu is no longer idle or about to enter idle. */
|
|
- sched_idle_set_state(NULL);
|
|
+ sched_idle_set_state(NULL, -1);
|
|
|
|
if (broadcast) {
|
|
if (WARN_ON_ONCE(!irqs_disabled()))
|