前言
有时候为了等待硬件设置生效,我们会在设置完硬件寄存器后,添加微小的延时函数。本次介绍linux内核中的延时函数。
一 短延迟
Linux内核中提供了下列3个函数以分别进行纳秒、微秒和毫秒延迟:
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
上述延迟的实现原理本质上是忙等待,它根据CPU频率进行一定次数的循环。有时候,人们在软件中进行下面的延迟:
void delay(unsigned int time)
{
while(time--);
}
ndelay()、udelay()和mdelay()函数的实现方式原理与此类似。内核在启动时,会运行一个延迟循环校准(Delay Loop Calibration),计算出lpj(Loops Per Jiffy),内核启动时会打印如下类似信息:
[ 0.003137] Calibrating delay loop (skipped), value calculated using timer frequency.. 6.00 BogoMIPS (lpj=30000)
如果我们直接在bootloader传递给内核的bootargs中设置lpj=30000,则可以省掉这个校准的过程,节省约百毫秒级的开机时间。毫秒时延(以及更大的秒时延)已经比较大了,在内核中,最好不要直接使用mdelay()函数,这将耗费CPU资源,对于毫秒级以上的时延,内核提供了下述函数:
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds);
上述函数将使得调用它的进程睡眠参数指定的时间为millisecs,msleep()、ssleep()不能被打断,而msleep_interruptible()则可以被打断。受系统Hz以及进程调度的影响,msleep()类似函数的精度是有限的。
二 在uboot中设置lpj=30000
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.0.11:/big/nfsroot/jiaocheng_rootfs,proto=tcp rw ip=192.168.0.3:192.168.0.11:192.168.0.1:255.255.255.0:::;lpj=30000;'
设置完毕后,启动内核,找到这条调试信息:
[ 0.003143] Calibrating delay loop (skipped), value calculated using timer frequency.. 6.00 BogoMIPS (lpj=30000)
并没有发现启动速度有超过百毫秒的提升。正如调试信息提示的一样Calibrating delay loop (skipped),计算过程跳过了,使用的是常量值。