您的位置:首页 > 文旅 > 旅游 > 河南网站建设技术公司_首页一卡通_百度竞价排名查询网站_seo推广一个月见效

河南网站建设技术公司_首页一卡通_百度竞价排名查询网站_seo推广一个月见效

2025/4/19 10:11:20 来源:https://blog.csdn.net/dahailinan/article/details/147245789  浏览:    关键词:河南网站建设技术公司_首页一卡通_百度竞价排名查询网站_seo推广一个月见效
河南网站建设技术公司_首页一卡通_百度竞价排名查询网站_seo推广一个月见效

1、框架

2、休眠流程
应用层通过echo mem > /sys/power/state写入休眠状态,给一张大概流程图

这个操作对应在kernel/power/main.c的state这个attr的store操作

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
                           const char *buf, size_t n)
{
        suspend_state_t state;
        int error;
 
        error = pm_autosleep_lock();
        if (error)
                return error;
 
        if (pm_autosleep_state() > PM_SUSPEND_ON) {
                error = -EBUSY;
                goto out;
        }
 
        state = decode_state(buf, n);
        if (state < PM_SUSPEND_MAX) {
                if (state == PM_SUSPEND_MEM)
                        state = mem_sleep_current;
 
                error = pm_suspend(state);
        } else if (state == PM_SUSPEND_MAX) {
                error = hibernate();
        } else {
                error = -EINVAL;
        }
 
 out:
        pm_autosleep_unlock();
        return error ? error : n;
}

应用层通过/sys/power/state写入休眠状态;或者使能autosleep都会调用这个

int pm_suspend(suspend_state_t state)
{
    int error;
 
    if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
        return -EINVAL;
 
    pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
    error = enter_state(state);
    if (error) {
        suspend_stats.fail++;
        dpm_save_failed_errno(error);
    } else {
        suspend_stats.success++;
    }
    pr_info("suspend exit\n");
    return error;
}

不同state,进入不同休眠状态

static int enter_state(suspend_state_t state)
{
    int error;
 
    trace_suspend_resume(TPS("suspend_enter"), state, true);
    if (state == PM_SUSPEND_TO_IDLE) {
#ifdef CONFIG_PM_DEBUG
        if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
            pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n");
            return -EAGAIN;
        }
#endif
    } else if (!valid_state(state)) {
        return -EINVAL;
    }
    if (!mutex_trylock(&system_transition_mutex))
        return -EBUSY;
 
    if (state == PM_SUSPEND_TO_IDLE)
        s2idle_begin();
 
    if (sync_on_suspend_enabled) {
        trace_suspend_resume(TPS("sync_filesystems"), 0, true);
        ksys_sync_helper();
        trace_suspend_resume(TPS("sync_filesystems"), 0, false);
    }
 
    pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
    pm_suspend_clear_flags();
    error = suspend_prepare(state);
    if (error)
        goto Unlock;
 
    if (suspend_test(TEST_FREEZER))
        goto Finish;
 
    trace_suspend_resume(TPS("suspend_enter"), state, false);
    pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]);
    pm_restrict_gfp_mask();
    error = suspend_devices_and_enter(state);
    pm_restore_gfp_mask();
 
 Finish:
    events_check_enabled = false;
    pm_pr_dbg("Finishing wakeup.\n");
    suspend_finish();
 Unlock:
    mutex_unlock(&system_transition_mutex);
    return error;
}

设备进入休眠,被唤醒或者休眠失败,就会走对应的唤醒流程;

挂起console,比如串口,终端等;

挂起devfreq,cpufreq;执行device_suspend

int suspend_devices_and_enter(suspend_state_t state)
{
    int error;
    bool wakeup = false;
 
    if (!sleep_state_supported(state))
        return -ENOSYS;
 
    pm_suspend_target_state = state;
 
    if (state == PM_SUSPEND_TO_IDLE)
        pm_set_suspend_no_platform();
 
    error = platform_suspend_begin(state);
    if (error)
        goto Close;
 
    suspend_console();//挂起console,比如串口,终端等
    suspend_test_start();
    error = dpm_suspend_start(PMSG_SUSPEND);//挂起devfreq,cpufreq;执行device_suspend
    if (error) {
        pr_err("Some devices failed to suspend, or early wake event detected\n");
        goto Recover_platform;
    }
    suspend_test_finish("suspend devices");
    if (suspend_test(TEST_DEVICES))
        goto Recover_platform;
 
    do {
        error = suspend_enter(state, &wakeup);//平台休眠
    } while (!error && !wakeup && platform_suspend_again(state));
 
 Resume_devices:
    suspend_test_start();
    dpm_resume_end(PMSG_RESUME);
    suspend_test_finish("resume devices");
    trace_suspend_resume(TPS("resume_console"), state, true);
    resume_console();
    trace_suspend_resume(TPS("resume_console"), state, false);
 
 Close:
    platform_resume_end(state);
    pm_suspend_target_state = PM_SUSPEND_ON;
    return error;
 
 Recover_platform:
    platform_recover(state);
    goto Resume_devices;
}

平台进入休眠;被唤醒或者休眠失败,就会走对应的唤醒流程;

检查pendind标记,检查休眠锁标记,来进入平台实现的enter函数;

平台休眠的最后,会开启中断,用与响应外部中断,来唤醒系统并继续执行接下来的代码唤醒系统

static int suspend_enter(suspend_state_t state, bool *wakeup)
{
    int error;
 
    error = platform_suspend_prepare(state);
    if (error)
        goto Platform_finish;
 
    error = dpm_suspend_late(PMSG_SUSPEND);
    if (error) {
        pr_err("late suspend of devices failed\n");
        goto Platform_finish;
    }
    error = platform_suspend_prepare_late(state);
    if (error)
        goto Devices_early_resume;
 
    error = dpm_suspend_noirq(PMSG_SUSPEND);
    if (error) {
        pr_err("noirq suspend of devices failed\n");
        goto Platform_early_resume;
    }
    error = platform_suspend_prepare_noirq(state);
    if (error)
        goto Platform_wake;
 
    if (suspend_test(TEST_PLATFORM))
        goto Platform_wake;
 
    if (state == PM_SUSPEND_TO_IDLE) {
        s2idle_loop();
        goto Platform_wake;
    }
 
    error = pm_sleep_disable_secondary_cpus();
    if (error || suspend_test(TEST_CPUS))
        goto Enable_cpus;
 
    arch_suspend_disable_irqs();
    BUG_ON(!irqs_disabled());
 
    system_state = SYSTEM_SUSPEND;
 
    error = syscore_suspend();
    if (!error) {
        *wakeup = pm_wakeup_pending();//检查能否进休眠
        if (!(suspend_test(TEST_CORE) || *wakeup)) {
            trace_suspend_resume(TPS("machine_suspend"),
                state, true);
            error = suspend_ops->enter(state);
            trace_suspend_resume(TPS("machine_suspend"),
                state, false);
        } else if (*wakeup) {
            error = -EBUSY;
        }
        syscore_resume();
    }
 
    system_state = SYSTEM_RUNNING;
 
    arch_suspend_enable_irqs();//平台休眠,但是开启中断,用与响应中断,唤醒系统并继续执行接下来的代码唤醒系统
    BUG_ON(irqs_disabled());
 
 Enable_cpus:
    pm_sleep_enable_secondary_cpus();
 
 Platform_wake:
    platform_resume_noirq(state);
    dpm_resume_noirq(PMSG_RESUME);
 
 Platform_early_resume:
    platform_resume_early(state);
 
 Devices_early_resume:
    dpm_resume_early(PMSG_RESUME);
 
 Platform_finish:
    platform_resume_finish(state);
    return error;
}

3、两种阻止进入休眠
最终都是通过__pm_stay_awake

应用层
echo abc > /sys/power/wake_lock 来申请一个休眠锁;

使用cat /sys/kernel/debug/wakeup_sources看什么在持有休眠锁; 

echo abc > /sys/power/wake_unlock来接触休眠锁

内核层
应用请求休眠,系统进入休眠流程,此时如果设备触发了中断,中断处理程序中首先关闭中断,然后调度内核线程去处理work,但假如这个时候此work还未被调度到,系统就进入休眠了,那么这个设备就被永久关闭中断了,再也不能唤醒系统。pm_stay_awake()和pm_relax()的设计就是用来解决这个问题。

pm_stay_awake
        pm_wake_lock
                __pm_stay_awake
恢复
        pm_wake_unlock
                __pm_relax


休眠检查
pm_wakeup_pending


示例:休眠后,无法唤醒?


开启打印信息
休眠后系统卡住,组织串口来休眠,并开启相关打印;在Linux内核睡眠过程中,会先调用suspend_console()函数使串口进入睡眠状态,这样会导致后续设备驱动的睡眠过程不可见。可以在boot启动参数中增加no_console_suspend参数,显示设备驱动睡眠日志

remove_cmdline_param(cmdline, "no_console_suspend");
sprintf(cmdline + strlen(cmdline), " no_console_suspend=%d", 1);
修改串口日志打印等级,显示更多调试信息

echo 8 > /proc/sys/kernel/printk
设置pm_print_times参数,可以显示设备驱动睡眠唤醒时间,方便调试时查看哪个函数处理占用时间过长

echo 1 > /sys/power/pm_print_times
设置pm_debug_messages,打印来自系统的调试消息的暂停/休眠内核日志的基础结构

echo 1 > /sys/power/pm_debug_messages
打印信息
PM: pm_system_irq_wakeup: 20 triggered PMIC
pxa2xx-i2c pxa2xx-i2c.2: calling i2c_pxa_suspend_noirq+0x1/0x24 @ 6223, parent: d4000000.apb
i2c: <pxa_i2c-i2c> ICR is modified!
pxa2xx-i2c pxa2xx-i2c.2: i2c_pxa_suspend_noirq+0x1/0x24 returned 0 after 0 usecs
i2c: reset controller!
Workqueue: events chargeic_update_state_work_func
pcie-falcon d4220000.pcie: calling pcie_resume_noirq+0x1/0x1c @ 6223, parent: d4200000.axi
PCIe Host: No link negotiated
pcie-falcon d4220000.pcie: pcie_resume_noirq+0x1/0x1c returned 0 after 114202 usecs
pci 0001:00:00.0: calling pci_pm_resume_noirq+0x1/0xd4 @ 6165, parent: pci0001:00
pxa2xx-i2c pxa2xx-i2c.0: calling i2c_pxa_resume_noirq+0x1/0x38 @ 6223, parent: d4000000.apb
解决办法
i2c还在工作----而且打印了正在工作的函数;确认是充电ic休眠函数没去暂停工作队列;实现PM函数即可修复

#ifdef CONFIG_PM
static int charger_suspend(struct device *dev)
{
        cancel_delayed_work_sync(g_info->chg_state_update_work);
        return 0;
}
 
static int charger_resume(struct device *dev)
{
        mod_delayed_work(system_wq, g_info->chg_state_update_work,msecs_to_jiffies(1000));
        return 0;
}
 
static const struct dev_pm_ops pm_ops = {
        .suspend = charger_suspend,
        .resume = charger_resume,
};
 
#endif

找不到pcie设备----确认供电;如无异常,确认cpu和ddr频率是否恢复;如无异常,确认现象是否跟复位脚异常有关

--- a/drivers/pci/controller/pcie-host.c
+++ b/drivers/pci/controller/pcie-host.c
@@ -646,6 +646,7 @@ static int __maybe_unused pcie_suspend_noirq(struct device *dev)
        phy_exit(port->phy);
        pm_qos_update_request(&pcie->qos_idle,
                        PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE);
+       gpio_set_value(port->gpio_reset,0);
        return 0;
 }
 
@@ -653,10 +654,10 @@ static int __maybe_unused pcie_resume_noirq(struct device *dev)
 {
        struct pcie *pcie = dev_get_drvdata(dev);
        struct pcie_port *port = pcie->port;
-
+       gpio_set_value(port->gpio_reset,1);
+       mdelay(200);
        pm_qos_update_request(&pcie->qos_idle, port->lpm_qos);
        pcie_enable_port(port);
        return 0;
 }

修改后系统可被正常唤醒

4、echo mem > /sys/power/state

做如上操作后,整个函数调用流程如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com