suspend小节

suspend小节

概括:
事件触发-----》
1.PowerManagerService----》
2.Native AutoSuspend----》
3.Autosuspend Driver----》
4.(Suspend kworks:freezing tasks -> devices level suspend -> system level suspend -> platform level suspend -> cpu enter WFI)----》
5.SPM

代码追踪:
上层接收到事件,通过power manager service操作位于sys/power的节点:

上层会调用autosuspend_enable()函数
//system/core/libsuspend/autosuspend.c

int autosuspend_enable(void)
{
    autosuspend_init();
    autosuspend_ops->enable();   
}

int autosuspend_disable(void)
{
    autosuspend_init();
    autosuspend_ops->disable();
}

static int autosuspend_init(void)
{   
    autosuspend_ops = autosuspend_wakeup_count_init();
}

//system/core/libsuspend/autosuspend_wakeup_count.c

#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
struct autosuspend_ops *autosuspend_wakeup_count_init(void)
{
	wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
	pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
}
 
//没有锁,写mem>/sys/power/state
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
    while (1) {
        usleep(100000);
        wakeup_count_len = read(wakeup_count_fd, wakeup_count,sizeof(wakeup_count));
        sem_wait(&suspend_lockout);
 
        ret=write(wakeup_count_fd, wakeup_count, wakeup_count_len));
        if (ret < 0) 
        {
        }
        else
        {
            write(state_fd, sleep_state, strlen(sleep_state)); 
        }
    }
}
 
static int autosuspend_wakeup_count_enable(void)
{
    sem_post(&suspend_lockout);
}
 
static int autosuspend_wakeup_count_disable(void)
{
    sem_wait(&suspend_lockout);
}

//kernel/kernel/power/main.c

static ssize_t wakeup_count_show(struct kobject *kobj,struct kobj_attribute *attr,char *buf)
{
    unsigned int val;
    return pm_get_wakeup_count(&val, true) ?
		sprintf(buf, "%u\n", val) : -EINTR;
}

static ssize_t wakeup_count_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{
	unsigned int val;
	error = -EINVAL;
	if (sscanf(buf, "%u", &val) == 1) {
		if (pm_save_wakeup_count(val))
			error = n;
	}

 out:
	return error;
}
power_attr(wakeup_count);

bool pm_get_wakeup_count(unsigned int *count, bool block)
{
	unsigned int cnt, inpr;
	if (block) {
		DEFINE_WAIT(wait);

		for (;;) {
			prepare_to_wait(&wakeup_count_wait_queue, &wait,
					TASK_INTERRUPTIBLE);
			split_counters(&cnt, &inpr);
			if (inpr == 0 || signal_pending(current))
				break;

			schedule();
		}
		finish_wait(&wakeup_count_wait_queue, &wait);
	}

	split_counters(&cnt, &inpr);
	*count = cnt;
	return !inpr;
}

/**
 * pm_save_wakeup_count - Save the current number of registered wakeup events.
 * @count: Value to compare with the current number of registered wakeup events.
 *
 * If @count is equal to the current number of registered wakeup events and the
 * current number of wakeup events being processed is zero, store @count as the
 * old number of registered wakeup events for pm_check_wakeup_events(), enable
 * wakeup events detection and return 'true'.  Otherwise disable wakeup events
 * detection and return 'false'.
 */
bool pm_save_wakeup_count(unsigned int count)
{
	unsigned int cnt, inpr;
	unsigned long flags;

	events_check_enabled = false;
	spin_lock_irqsave(&events_lock, flags);
	split_counters(&cnt, &inpr);
	if (cnt == count && inpr == 0) {
		saved_count = count;
		events_check_enabled = true;
	}
	spin_unlock_irqrestore(&events_lock, flags);
	return events_check_enabled;
}

/*
上面的作用是对/sys/power/wakeup_count进行读写(涉及到变量combined_event_count,

可参考https://blog.csdn.net/mike8825/article/details/80422993),如果所有的锁都已解锁,

则写"mem"到/sys/power/state进行休眠*/

/********************************************************************************************************************************************************

简单总结:

autosuspend_enable() -> autosuspend_init() -> autosuspend_wakeup_count_init()此时“/sys/power/wakeup_count”节点已经打开,方便后面计数操作 ->  当确认没有锁时转到suspend_thread_func()先给wakeup_count写值,再为state节点写值mem

********************************************************************************************************************************************************/

sys/power/state节点生成于:kernel/kernel/power/main.c
当对该节点进行写操作时会调用函数state_store()

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{
    state = decode_state(buf, n);//将"mem"转换成对应的数字
    error = pm_suspend(state);
}
 
int pm_suspend(suspend_state_t state)
{
	pm_suspend_marker("entry");
	error = enter_state(state);
	pm_suspend_marker("exit");
}
 
static void pm_suspend_marker(char *annotation)
{
	struct timespec ts;
	struct rtc_time tm;
 
	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",
		annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
		tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
 
 
static int enter_state(suspend_state_t state)
{
	printk(KERN_INFO "PM: Syncing filesystems ... ");
	sys_sync();
	printk("done.\n");
 
	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
	error = suspend_prepare(state);
 
	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
	pm_restrict_gfp_mask();
	error = suspend_devices_and_enter(state);
	pm_restore_gfp_mask();
 
 Finish:
	pr_debug("PM: Finishing wakeup.\n");
	suspend_finish();
}
 
static inline int suspend_freeze_processes(void)
{
	error = freeze_processes();
	error = freeze_kernel_threads();
}
 
static int suspend_prepare(suspend_state_t state) //冻结所有进程
{
	if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter))   //kernel/drivers/cpuidle/lpm-levels.c	suspend_set_ops(&lpm_suspend_ops);
		return -EPERM;  
	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
	error = suspend_freeze_processes();
	pm_notifier_call_chain(PM_POST_SUSPEND);
	return error;
}
 
int suspend_devices_and_enter(suspend_state_t state)
{
	int error;
	bool wakeup = false;
 
	if (need_suspend_ops(state) && !suspend_ops)
		return -ENOSYS;
 
	if (need_suspend_ops(state) && suspend_ops->begin) {
		error = suspend_ops->begin(state);
		if (error)
			goto Close;
	}
	suspend_console();
	error = dpm_suspend_start(PMSG_SUSPEND);
	if (error) {
		printk(KERN_ERR "PM: Some devices failed to suspend\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 && need_suspend_ops(state)
		&& suspend_ops->suspend_again && suspend_ops->suspend_again());
 
 Resume_devices:
	dpm_resume_end(PMSG_RESUME);
	resume_console();
 Close:
	if (need_suspend_ops(state) && suspend_ops->end)
		suspend_ops->end();
	return error;
 
 Recover_platform:
	if (need_suspend_ops(state) && suspend_ops->recover)
		suspend_ops->recover();
	goto Resume_devices;
}
 
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
	error = dpm_suspend_end(PMSG_SUSPEND);
	error = disable_nonboot_cpus();
	arch_suspend_disable_irqs();
	error = syscore_suspend();
	if (!error) {
		*wakeup = pm_wakeup_pending();
		if (!(suspend_test(TEST_CORE) || *wakeup)) {
			error = suspend_ops->enter(state);//停在这..........
			events_check_enabled = false;
		}
		syscore_resume();
	}
	arch_suspend_enable_irqs();
 Enable_cpus:
	enable_nonboot_cpus();
 
 Platform_wake:
	if (need_suspend_ops(state) && suspend_ops->wake)
		suspend_ops->wake();
 
	dpm_resume_start(PMSG_RESUME);
 
 Platform_finish:
	if (need_suspend_ops(state) && suspend_ops->finish)
		suspend_ops->finish();
 
	return error;
}

/********************************************************************************************************************************************************
简单总结:

对state节点进行写操作会调用:state_store() -> pm_suspend() -> enter_state() ->  suspend_prepare()准备冻结进程 ->  suspend_freeze_processes()冻结所有进程
																		   |>  suspend_devices_and_enter() -> suspend_ops->begin()->dpm_suspend_start()会依次调用驱动的suspend() 回调来休眠掉所有的设备。
																										  |--> suspend_enter() -> suspend_ops->enter()最终停在这里,这个函数会关闭arch irq, 调用 device_power_down(), 
																										  它会调用suspend_late()函数, 这个函数是系统真正进入休眠最后调用的函数,通常会在这个函数中作最后的检查。 如果检查没问题, 
																										  接下来休眠所有的系统设备和总线,并且调用 suspend_pos->enter() 来使CPU进入省电状态,这时就已经休眠了。代码的执行也就停在这里了。

********************************************************************************************************************************************************/

首先有一个suspend事件,上层服务会使能autosuspend,接着修改count数值,判断是否有wakeup_lock被占用,若没有,向steat节点写值。
写值会调用一系列函数,先冻结进程,之后遍历执行设备链表中各个设备的suspend函数(dpm_suspend_start()),在关闭arch irq,休眠所有设备和总线(suspend_ops->enter())。
其中有任意一环不符合条件就会终止suspend,恢复之前的状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值