• kernel syscore 学习笔记 Hello


    一、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

  • 相关阅读:
    tensorflow2中pydot问题
    tensorflow2的差异总结
    tensorflow2.0中引入keras和原来的keras的差异
    Linux 后台任务进程管理工具supervisor的使用
    【Go学习】go 原生库net/http发送 GET POST 请求
    正则校验crontab格式
    【FastAPI 学习十二】定时任务篇
    【FastAPI 学习 十一】 项目目录结构demo(自己改版)
    【FastAPI 学习 十】使用Redis
    【FastAPI 学习 九】图片文件上传
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/16225836.html
Copyright © 2020-2023  润新知