ARM Linux size kernel switch -cortex-a7 big. LITTLE size switch Code Analysis
8-core CPUs or more cores, these CPUs may not be completely symmetrical. There are 4 A15 and 4 A7, or 4 A57 and 4 A53, even like HiSilicon Kylin 935 processor (4 Core A53 2.2 GHz + 4 core A53 1.5 GHz), the frequencies of these 8 cores may not be the same, then the use of the process requires the size of the core switch (high frequency is the large core, The low frequency is the small nucleus). This paper takes arm cortex-a7 as an example to analyze the code of size and core switching , focusing on the analysis of switching code, for why this switch, and when to switch, do not do too much discussion.
Main code Distribution:
Arch/arm/common/bl_switcher.c
Arch/arm/include/asm/bl_switcher.h
Drivers/cpufreq/arm_big_little.c
Two drive modules formed after compilation:
__initcall_bl_switcher_init6
__initcall_bl_cpufreq_register7
The execution flowchart is shown below.
On the left is the Bl_switcher_init execution process.
On the right is the switch thread bl_switcher_thread execution process, which is the core code. The upper part of the code is a CPU that is running, and then this CPU completes the power-down. The lower half is shown in blue, and the CPU that is up is running, which completes the switching operation of the size core.
1 Bl_switcher_init
The Bl_switcher_init execution process is as follows:
If the maximum number of CPU groups (clusters) is not 2, an error is then returned
Bl_running_cluster is assigned a value of 1, which is set by default to be the first cluster running
No_bl_switcher initial value is False
Bl_switcher_enable
Bl_switcher_halve_cpus shutdown of unnecessary CPUs
Create a toggle thread for each of the online CPUs Bl_switcher_thread
bl_switcher_active assigned value 1
Bl_switcher_sysfs_init creating sys/kernel/bl_switcher
Bl_switcher_restore_unpaired_cpus Restore the unpaired CPUs, power them up.
After you create the Sys/kernel/bl_switcher, you can manually view/set the ability to toggle, view/Set the CPU switching between the clusters by using the command below.
cat/sys/kernel/bl_switcher/active
echo 0/1 >/sys/kernel/bl_switcher/active
Cat/sys/kernel/bl_switcher/do_switch
echo 0/1 >/sys/kernel/bl_switcher/do_switch
2 Switching Request Bl_switch_request
This is an inline function, requires two parameters, the first one is the CPU ID, the second is the cluster number, the kernel is transferred to three places.
One is in Arm_big_little.c:bl_cpufreq_set_rate: when different cluster switching is required;
Second, three is in the implementation of ECHO 0/1 >/sys/kernel/bl_switcher/do_switch, call to Bl_do_switch_store function, which determines whether the need to switch
This inline function executes the BL_SWITCH_REQUEST_CB directly, with the arguments being 2 preceding, plus two null.
BL_SWITCH_REQUEST_CB:
Determines whether the ID of the first parameter CPU is out of range;
Gets the thread function pointer for the current CPU
Assignment Wanted_cluster
Wakes the work queue of the current thread function
3 Toggle Thread Bl_switcher_thread
Bl_switcher_thread Execution Process:
Wait for the event. Two possible conditions to meet the event:
One is the BL_SWITCH_REQUEST_CB function above, wake up the thread, and switch to the number of CPU clusters is not-1;
The second is the bl_switcher_disable function called Kthread_stop, which wakes up the thread
Bl_switch_to
Find paired CPU ID, cluster number
Mcpm_cpu_power_up to power the CPU, jump to Mcpm_entry_point
Gic_send_sgi send it a soft interrupt number No. 0
Wait_for_completion_timeout (&inbound_alive wait for it to send me a soft interrupt ipi_completion
Turn off IRQ, FIQ
Migration interrupted to the corresponding CPU
Turn off clock tick
Cpu_pm_enter Gic_cpu_save Save Interrupt settings
Cpu_suspend , this is very similar to the sleep process.
Bl_switchpoint
call_with_stack arch/arm/lib/call_with_stack. If S fails, it can be returned.
Bl_do_switch
Let the newly-up CPU jump to cpu_resumeand send it SEv
If the handshake variable is 0, enter the WFE
After the wait is not 0, the Mcpm_cpu_power_down power to itself
call_with_stack: Three parameters to carry, the first is the function, the second is the parameter used in the function call, and the third is the stack address
Place SP, LR into the top of the stack in turn
SP assignment the address after two registers
R0 Fu to R2
R1 Fu to R0
LR Assignment below the label 1 place
R2 to the PC, that is, jump to R2
If it fails, it jumps to LR, marking 1.
Eject LR
Eject SP
LR assigns to the PC, jumps to the bl_switchpoint, calls the call_with_stack function Place.
The setting here is really ingenious, the CPU ID of the different clusters is 0, then the CPU that just got up can pass the following steps
Mcpm_entry_point, cpu_resume , Cpu_do_resume=cpu_v7_do_resume, Cpu_resume_mmu, again jump to the above call __ The cpu_suspend continues to run.
that is to power down the CPU just after the stack is saved, and the CPU is just on the power resumed.
The next step is to power up the CPU and run it again.
Cpu_pm_exit Gic_cpu_restore Recovery Interrupt settings
The clock then runs Tick, and the two CPU beats timer is the same.
Open IRQ, FIQ
*handshake_ptr = 1;
Dsb_sev send events to that CPU
This completes the CPU switchover, the first half of this function is a CPU in execution, and the second half becomes the other CPU in the execution.
4 Bl_cpufreq_register
Get the value of bl_switcher_active, set this value (TRUE or false) to the bl_switching_enabled variable;
Initialize the mutex lock cluster_lock;
Register Cpufreq_driver driver Bl_cpufreq_driver.
If the above driver registration is successful, the Bl_switcher_notifier is hung on the bl_activation_notifier linked list;
If mount fails, uninstall driver Bl_cpufreq_driver
Bl_cpufreq_driver is defined as follows:
static struct Cpufreq_driver Bl_cpufreq_driver = {
. Name = "Arm-big-little",
. Flags = Cpufreq_sticky,
. Verify = Bl_cpufreq_verify_policy,
. target = Bl_cpufreq_set_target,
. get = Bl_cpufreq_get_rate,
. init = Bl_cpufreq_init,
. Have_governor_per_policy = True,
. attr = Bl_cpufreq_attr,
};
If the Bl_cpufreq_driver registration succeeds, execute the following command, you can see that there is a driver is arm-big-little.
Cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
Conservative OnDemand userspace PowerSave Interactive performance
Cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_governors
Interactive
Cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver
arm-big-little
With BL_CPUFREQ_DRIVER this FM policy, it executes to bl_cpufreq_set_target and then executes Bl_cpufreq_set_rate, and it is possible to call to Bl_switch_request.
ARM Linux size kernel switch--cortex-a7 big. LITTLE size Kernel switch code Analysis