kernel syscore 学习笔记

一、syscore简介

1. syscore 作为低功耗休眠唤醒流程的一部分,其涉及的文件主要有 syscore_ops.h 和 syscore.c,这一级别的回调函数是在完全屏蔽中断的场景下进行的。

2. 相关结构

//syscore_ops.h
struct syscore_ops {
    struct list_head node;
    int (*suspend)(void); //syscore_suspend()中遍历调用此回调
    void (*resume)(void); //syscore_resume()中遍历调用此回调
    void (*shutdown)(void); //syscore_shutdown()中遍历调用此回调
};

使用时可以提供一个或多个回调函数的实现。

3. 相关函数

//syscore.c
void register_syscore_ops(struct syscore_ops *ops);
void unregister_syscore_ops(struct syscore_ops *ops);

 

二、使用方法

1. 使用时定义一个 struct syscore_ops 结构变量,然后实现感兴趣的回调函数。之后调用 register_syscore_ops() 进行注册,当移除驱动时,调用 unregister_syscore_ops() 去掉注册。

2. register_syscore_ops()/unregister_syscore_ops() 的实现

//syscore.c
void register_syscore_ops(struct syscore_ops *ops)
{
    mutex_lock(&syscore_ops_lock);
    list_add_tail(&ops->node, &syscore_ops_list); //注意是尾插法
    mutex_unlock(&syscore_ops_lock);
}
EXPORT_SYMBOL_GPL(register_syscore_ops);

void unregister_syscore_ops(struct syscore_ops *ops)
{
    mutex_lock(&syscore_ops_lock);
    list_del(&ops->node);
    mutex_unlock(&syscore_ops_lock);
}
EXPORT_SYMBOL_GPL(unregister_syscore_ops);

 

三、调用时机

1. suspend 回调位置

int syscore_suspend(void)
{
    struct syscore_ops *ops;
    int ret = 0;

    trace_suspend_resume(TPS("syscore_suspend"), 0, true);
    pm_pr_dbg("Checking wakeup interrupts\n");

    if (pm_wakeup_pending())
        return -EBUSY;

    WARN_ONCE(!irqs_disabled(),
        "Interrupts enabled before system core suspend.\n");

    //注意反向遍历,也就是最后注册的suspend回调函数最先被调用
    list_for_each_entry_reverse(ops, &syscore_ops_list, node)
        if (ops->suspend) {
            pm_pr_dbg("Calling %pS\n", ops->suspend);
            ret = ops->suspend();
            if (ret)
                goto err_out;
            WARN_ONCE(!irqs_disabled(),
                "Interrupts enabled after %pS\n", ops->suspend);
        }

    trace_suspend_resume(TPS("syscore_suspend"), 0, false);

    return 0;

    //只要有任何一个suspend回调失败了,就完整地回调一遍resume回调,注意不是从断点位置回调的!
 err_out:
    log_suspend_abort_reason("System core suspend callback %pS failed", ops->suspend);
    pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend);

    list_for_each_entry_continue(ops, &syscore_ops_list, node)
        if (ops->resume)
            ops->resume();

    return ret;
}
EXPORT_SYMBOL_GPL(syscore_suspend);

2. resume 回调位置

//syscore.c
void syscore_resume(void)
{
    struct syscore_ops *ops;

    trace_suspend_resume(TPS("syscore_resume"), 0, true);
    //说明是关着中断回调resume回调的
    WARN_ONCE(!irqs_disabled(), "Interrupts enabled before system core resume.\n");

    //注意,这个是正向遍历的,先注册的resume回调先被调用
    list_for_each_entry(ops, &syscore_ops_list, node)
        if (ops->resume) {
            pm_pr_dbg("Calling %pS\n", ops->resume);
            ops->resume();
            WARN_ONCE(!irqs_disabled(), "Interrupts enabled after %pS\n", ops->resume);
        }
    trace_suspend_resume(TPS("syscore_resume"), 0, false);
}
EXPORT_SYMBOL_GPL(syscore_resume);

3. shutdown 回调位置

void syscore_shutdown(void)
{
    struct syscore_ops *ops;

    mutex_lock(&syscore_ops_lock);

    //注意,这个也是反向调用的,最后注册的最先被调用
    list_for_each_entry_reverse(ops, &syscore_ops_list, node)
        if (ops->shutdown) {
            if (initcall_debug)
                pr_info("PM: Calling %pS\n", ops->shutdown);
            ops->shutdown();
        }

    mutex_unlock(&syscore_ops_lock);
}

4. 整机调用时机

echo mem > /sys/power/state
    state_store
        pm_suspend
            enter_state
                suspend_devices_and_enter
                    suspend_enter
                        platform_suspend_prepare
                        dpm_suspend_late
                        platform_suspend_prepare_late
                        dpm_suspend_noirq
                        platform_suspend_prepare_noirq
                        suspend_disable_secondary_cpus //关非boot cpu
                        arch_suspend_disable_irqs //关中断
                        syscore_suspend //syscore .suspend 回调
                        suspend_ops->enter //完全休眠下去,之后唤醒了从这里开始执行-------------------
                        syscore_resume //syscore .resume 回调
                        arch_suspend_enable_irqs //开中断
                        suspend_enable_secondary_cpus //开非boot cpu
                        platform_resume_noirq
                        dpm_resume_noirq
                        platform_resume_early
                        dpm_resume_early

4. 调用时机汇总

这些syscore ops的回调是关中断,关非boot cpu的情况下调用的。suspend/shutdown回调注册的越早越靠后调用,resume回调注册的越早越靠前调用。syscore的suspend回调是在所有驱动的suspend回调之后被调用,syscore的resume回调在所有驱动的resume回调之前被调用。

 

四、依赖关系处理

在probe()驱动的时候有考虑依赖关系,若发现自己不适合被probe,probe()函数就返回 -EPROBE_DEFER 来延迟probe()。

参考:
https://blog.csdn.net/adaptiver/article/details/52013245

 

posted on 2022-05-05 18:18  Hello-World3  阅读(1320)  评论(0编辑  收藏  举报

导航