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()))
 |