新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM Linux 大小核切換

        ARM Linux 大小核切換

        作者: 時間:2016-11-09 來源:網絡 收藏
        8核CPU或者是更多核的處理器,這些CPU有可能不完全對稱。有的是4個A15和4個A7,或者是4個A57和4個A53,甚至像海思麒麟935處理器(4核A53 2.2 GHz + 4核A53 1.5 GHz),這8個核的頻率可能不一樣,則使用過程中需要大小核切換(頻率高的是大核,頻率低的是小核)。本文以ARM cortex-A7為例,分析大小核切換的代碼,著重于分析實現切換的代碼,對于為什么要這樣切換、以及什么時候切換,不做過多探討。

        本文引用地址:http://www.104case.com/article/201611/317988.htm

        主要代碼分布:

        arch/arm/common/bL_switcher.c

        arch/arm/include/asm/bL_switcher.h

        drivers/cpufreq/Arm_big_little.c

        編譯后形成的兩個驅動模塊:

        __initcall_bL_switcher_init6

        __initcall_bL_cpufreq_register7

        執行流程圖如下所示。

        上圖的左邊是bL_switcher_init執行流程。

        右邊是切換線程bL_switcher_thread執行流程,這個線程是核心代碼。代碼的上半部分是一個CPU在運行,然后這個CPU完成下電后。下半部分藍色所示,是起來的那個CPU在運行,這樣就完成了大小核的切換操作。

        1 bL_switcher_init

        bL_switcher_init執行流程如下:

        如果最大CPU組數(簇)不為2,則報錯,然后返回

        bL_running_cluster賦值1,默認設為是第一簇在運行

        no_bL_switcher初值為FALSE

        bL_switcher_enable

        bL_switcher_halve_cpus 關閉不必要的CPU

        為每個online的CPU創建切換線程bL_switcher_thread

        bL_switcher_active賦值1

        bL_switcher_sysfs_init 創建sys/kernel/bL_switcher

        bL_switcher_restore_unpaired_cpus 恢復不成對的CPU,給它們上電

        創建完sys/kernel/bL_switcher,則可以通過下面的命令,手動查看/設置能否切換、查看/設置切換那個簇的CPU。

        cat /sys/kernel/bL_switcher/active

        echo 0/1 > /sys/kernel/ bL_switcher/active

        cat /sys/kernel/bL_switcher/do_switch

        echo0/1> /sys/kernel/ bL_switcher/ do_switch

        2 切換請求bL_switch_request

        這是個內聯函數,需要兩個參數,第一個是CPU的ID,第二個是簇號,內核調到的有三處。

        一是在Arm_big_little.c:bL_cpufreq_set_rate:需要不同的簇切換時;

        二、三是在執行echo 0/1 > /sys/kernel/ bL_switcher/ do_switch ,調用到bL_do_switch_store函數,這里面判斷是否需要切換

        這個內聯函數,直接執行bL_switch_request_cb,參數是前面的2個,再加上兩個NULL。

        bL_switch_request_cb:

        判斷第一個參數CPU的ID是否超出范圍;

        獲取當前CPU的線程函數指針

        賦值wanted_cluster

        喚醒當前線程函數的工作隊列

        3 切換線程bL_switcher_thread

        bL_switcher_thread執行流程:

        等待事件。滿足事件的兩個可能條件:

        一是上面的bL_switch_request_cb函數,喚醒線程,且切換到的CPU簇數不為-1;

        二是bL_switcher_disable函數調用kthread_stop,喚醒線程

        bL_switch_to

        找到成對的CPU ID ,簇號

        mcpm_cpu_power_up 給CPU上電,跳轉到 mcpm_entry_point

        gic_send_sgi 給其發送0號軟中斷

        wait_for_completion_timeout(&inbound_alive 等待它給我發送軟中斷 IPI_COMPLETION

        關閉IRQ、FIQ

        遷移中斷到對應的CPU上

        關閉時鐘Tick

        cpu_pm_enter gic_cpu_save 保存中斷設置

        cpu_suspend這個跟睡眠的流程很相似

        bL_switchpoint

        call_with_stack arch/arm/lib/call_with_stack.S 若失敗了,是可以返回的

        bL_do_switch

        讓剛起來的CPU跳轉到cpu_resume,給其發送sev

        若handshake變量為0,則進入wfe

        等待不為0后,mcpm_cpu_power_down對自身斷電

        call_with_stack:攜帶的三個參數,第一個是函數,第二個是函數調用時用到的參數,第三個是棧地址

        將SP、LR依次放入棧的頂部

        SP賦值讓開兩個寄存器后的地址

        R0賦給R2

        R1賦給R0

        LR賦值下面的標號1處

        R2賦給PC,即跳轉到R2

        若失敗了,則跳轉到LR處,就是標號1處

        彈出LR

        彈出SP

        LR賦給PC,跳轉到了bL_switchpoint,調用call_with_stack函數的地方。

        此處設置真是巧妙,不同簇對應的CPU ID都是0,則剛起來的CPU正好能通過下面的步驟

        mcpm_entry_point-> cpu_resume-> cpu_do_resume=cpu_v7_do_resume -> cpu_resume_mmu -> 再次跳轉到上面調用__cpu_suspend處繼續運行了。

        即要下電的CPU剛保存后堆棧,又被剛上電的CPU恢復了。

        接下來就是上電的CPU再運行了。

        cpu_pm_exit gic_cpu_restore 恢復中斷設置

        時鐘接著運行 Tick,兩個CPU用到的節拍Timer是同一個。

        開啟IRQ、FIQ

        *handshake_ptr = 1;

        dsb_sev 給那個CPU發送事件

        這樣就完成了CPU的切換,這個函數的前一半是一個CPU在執行,后一半變成了另一個CPU在執行。

        4 bL_cpufreq_register

        獲取bL_switcher_active的值,將這個值(真或者假)設置給bL_switching_enabled變量;

        初始化互斥鎖cluster_lock;

        注冊cpufreq_driver驅動bL_cpufreq_driver。

        如果上面的驅動注冊成功,則將bL_switcher_notifier 掛在bL_activation_notifier鏈表上;

        若掛載失敗,則卸載驅動bL_cpufreq_driver

        bL_cpufreq_driver定義如下:

        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,

        };

        若bL_cpufreq_driver注冊成功,執行下面的命令,就可以看到有個驅動是arm-big-little。

        cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

        conservative ondemand userspace powersaveinteractiveperformance

        cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governors

        interactive

        cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver

        arm-big-little

        用bL_cpufreq_driver這種調頻策略時,就會執行到bL_cpufreq_set_target,然后執行bL_cpufreq_set_rate,則有可能調用到bL_switch_request。



        關鍵詞: ARMLinux大小核切

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 定安县| 汶上县| 百色市| 客服| 陈巴尔虎旗| 龙泉市| 筠连县| 即墨市| 五指山市| 凉山| 西盟| 集安市| 望江县| 新郑市| 普兰县| 珠海市| 二手房| 台南县| 永福县| 厦门市| 旌德县| 乳源| 清涧县| 扶绥县| 武乡县| 忻州市| 康马县| 朝阳县| 靖西县| 海门市| 仁寿县| 杭州市| 忻城县| 额敏县| 泗阳县| 巴东县| 吴忠市| 依安县| 寻乌县| 鹤山市| 津市市|