时间子系统1_时钟事件设备管理(四)
ockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
//cpu下一个事件的到期时间小于全局广播设备下一个事件的到期时间,设置cpu在下一个周期到期
if (dev->next_event.tv64 < bc->next_event.tv64)
tick_broadcast_set_event(dev->next_event, 1);
}
//cpu离开省电模式,全局广播设备不再接管其tick device的任务
} else {
//清除cpu关闭状态
if (cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
cpumask_clear_cpu(cpu, tick_get_broadcast_oneshot_mask());
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
//重新编程cpu的tick device在下一个周期到期
if (dev->next_event.tv64 != KTIME_MAX)
tick_program_event(dev->next_event, 1);
}
}
out:
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
// 选择do_timer cpu
// 调用路径:tick_notify->tick_handover_do_timer
4.1 static void tick_handover_do_timer(int *cpup)
{
//如果dying cpu负责do_timer,重新选取online cpu中第一个cpu负责
if (*cpup == tick_do_timer_cpu) {
int cpu = cpumask_first(cpu_online_mask);
tick_do_timer_cpu = (cpu < nr_cpu_ids) cpu :
TICK_DO_TIMER_NONE;
}
}
// dead cpu的clockevent的处理:
// 1.从oneshot掩码中删除cpu
// 2.从broadcast掩码中删除cpu
// 3.关闭clockevent设备
// 3.1 设置该cpu tick device的clockevent为null
// 3.2 将clockevent设备链入clockevents_released
// 从oneshot掩码中删除cpu
// 调用路径:tick_notify->tick_shutdown_broadcast_oneshot
5.1 void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
{
unsigned long flags;
unsigned int cpu = *cpup;
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
//从oneshot掩码中删除dead cpu
cpumask_clear_cpu(cpu, tick_get_broadcast_oneshot_mask());
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
// 从broadcast掩码中删除cpu
// 调用路径:tick_notify->
tick_shutdown_broadcast
5.2 void tick_shutdown_broadcast(unsigned int *cpup)
{
struct clock_event_device *bc;
unsigned long flags;
unsigned int cpu = *cpup;
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
//从broadcast掩码中删除dead cpu
bc = tick_broadcast_device.evtdev;
cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
//广播组为空,停止全局广播广播设备
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
if (bc && cpumask_empty(tick_get_broadcast_mask()))
clockevents_shutdown(bc);
}
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
// 关闭cpu的clockevent设备
// 调用路径:tick_notify->tick_shutdown
5.3 static void tick_shutdown(unsigned int *cpup)
{
struct tick_device *td = &per_cpu(tick_cpu_device, *cpup);
struct clock_event_device *dev = td->evtdev;
unsigned long flags;
raw_spin_lock_irqsave(&tick_device_lock, flags);
td->mode = TICKDEV_MODE_PERIODIC;
//标记给定cpu的clockevent设备为不可用
if (dev) {
dev->mode = CLOCK_EVT_MODE_UNUSED;
//将clockevent链接到clockevents_released
clockevents_exchange_device(dev, NULL);
td->evtdev = NULL;
}
raw_spin_unlock_irqrestore(&tick_device_lock, flags);
}
// 挂起cpu的clockevent
// 调用路径:tick_notify->tick_suspend
6.1 static void tick_suspend(void)
{
struct tick_device *td = &__get_cpu_var(tick_cpu_device);
unsigned long flags;
//关闭cpu tick device的clockevent
raw_spin_lock_irqsave(&tick_device_lock, flags);
clockevents_shutdown(td->evtdev);
raw_spin_unlock_irqrestore(&tick_device_lock, flags);
}
// 恢复cpu的clockevent
// 调用路径:tick_notify->tick_resume
7.1 static void tick_resume(void)
{
struct tick_device *td = &__get_cpu_var(tick_cpu_device);
unsigned long flags;
//恢复广播
int broadcast = tick_resume_broadcast();
raw_spin_lock_irqsave(&tick_device_lock