时间子系统1_时钟事件设备管理(二)
u加入广播组bitmap中
// 1.2 如果cpu的clockevent设备为周期模式,关闭其clockevent
// 2.关闭广播模式
// 2.1 从广播组bitmap中删除cpu
// 2.2 如果cpu的clockevent设备为周期模式,恢复其clockevent
// 3.如果广播组为空
// 3.1 停止全局广播设备
// 4.否则
// 4.1 设置全局广播设备为单触发模式或周期模式
// 注:
// 1.全局广播设备tick_broadcast_device
// 2.每个cpu有各自的tick_device,选择其中一个充当全局广播设备
// 3.加入广播组的clockevent需要关闭其周期触发模式
2.2 static void tick_do_broadcast_on_off(unsigned long *reason)
{
struct clock_event_device *bc, *dev;
struct tick_device *td;
unsigned long flags;
int cpu, bc_stopped;
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
cpu = smp_processor_id();
//per cpu的tick device
td = &per_cpu(tick_cpu_device, cpu);
dev = td->evtdev;
//全局广播设备
bc = tick_broadcast_device.evtdev;
//设备不受电源状态的影响
if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
goto out;
//广播组是否为空
bc_stopped = cpumask_empty(tick_get_broadcast_mask());
switch (*reason) {
//开启cpu的广播模式
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
//当前cpu不在广播组中
if (!cpumask_test_cpu(cpu, tick_get_broadcast_mask())) {
//将cpu加入广播组
cpumask_set_cpu(cpu, tick_get_broadcast_mask());
//关闭周期触发模式的clockevent设备
if (tick_broadcast_device.mode ==
TICKDEV_MODE_PERIODIC)
clockevents_shutdown(dev);
}
break;
//关闭cpu的广播模式
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
if (!tick_broadcast_force &&
//从广播组中清除该设备
cpumask_test_cpu(cpu, tick_get_broadcast_mask())) {
cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
//恢复该设备的周期触发模式
if (tick_broadcast_device.mode ==
TICKDEV_MODE_PERIODIC)
tick_setup_periodic(dev, 0);
}
break;
}
//删除了广播组中最后一个设备
if (cpumask_empty(tick_get_broadcast_mask())) {
if (!bc_stopped)
{ //停止全局广播设备
clockevents_shutdown(bc);
}
} else if (bc_stopped) {
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
tick_broadcast_start_periodic(bc);
else
tick_broadcast_setup_oneshot(bc);
}
out:
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
// cpu进入\离开广播模式
// 当cpu进入省电模式时,由全局广播设备接管cpu的时间维护
// 调用路径:tick_notify->
tick_broadcast_oneshot_control
// 函数主要任务:
// 1.cpu进入省电模式,由全局广播设备接管其时间维护
// 1.1 设置cpu关闭状态,更新全局广播设备的到期时间
// 2.cpu离开省电模式,全局广播设备不再接管其时间维护
// 2.1 更新全局广播设备的到期时间
// 注:
// cpu在进入省电模式时,进入广播模式
// cpu在离开省电模式时,退出广播模式
3.1 void tick_broadcast_oneshot_control(unsigned long reason)
{
struct clock_event_device *bc, *dev;
struct tick_device *td;
unsigned long flags;
int cpu;
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
//电源状态变化不影响周期模式的全局广播设备
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
goto out;
bc = tick_broadcast_device.evtdev;
cpu = smp_processor_id();
td = &per_cpu(tick_cpu_device, cpu);
dev = td->evtdev;
//cpu的clockevent设备不受电源状态的影响
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
goto out;
//cpu进入省电模式,由全局广播设备接管其tick device的任务
if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) {
//设置cpu关闭状态
if (!cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
cpumask_set_cpu(cpu, tick_get_broadcast_oneshot_mask());
cl