Linux内核:udelay()返回太早了?

tan*_*-ce 6 linux kernel driver delayed-execution

我有一个需要微秒延迟的驱动程序.为了创建这个延迟,我的驱动程序正在使用内核的udelay函数.具体来说,有一个调用udelay(90):

iowrite32(data, addr + DATA_OFFSET);
iowrite32(trig, addr + CONTROL_OFFSET);

udelay(30);

trig |= 1;
iowrite32(trig, addr + CONTROL_OFFSET);

udelay(90); // This is the problematic call
Run Code Online (Sandbox Code Playgroud)

我们的设备存在可靠性问题.经过大量的调试,我们在90us过去之前将问题追溯到驱动程序恢复.(参见下面的"证据".)

我在Intel Pentium Dual Core(E5700)上运行内核版本2.6.38-11-generic SMP(Kubuntu 11.04,x86_64).

据我所知,文档声明udelay将延迟执行至少指定的延迟,并且是不可中断的.这个版本的内核是否有错误,或者我是否误解了udelay的使用?


为了说服自己这个问题是由于udelay过早返回引起的,我们向其中一个I/O端口提供了一个100kHz的时钟,并按如下方式实现了我们自己的延迟:

// Wait until n number of falling edges
// are observed
void clk100_delay(void *addr, u32 n) {
    int i;

    for (i = 0; i < n; i++) {
        u32 prev_clk = ioread32(addr);
        while (1) {
            u32 clk = ioread32(addr);
            if (prev_clk && !clk) {
                break;
            } else {
                prev_clk = clk;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

......现在司机完美无瑕.


作为最后一点,我发现一个讨论表明频率缩放可能导致*delay()系列函数行为不端,但这是在ARM邮件列表上 - 我假设这些问题在基于Linux x86的基础上不存在PC.

Bri*_*ain 2

E5700 有X86_FEATURE_CONSTANT_TSC但没有X86_FEATURE_NONSTOP_TSC。TSC 可能是udelay. 除非使用关联掩码绑定到其中一个核心,否则您的任务可能会在udelay. 或者 TSC 在低功耗 CPU 模式下可能不稳定。

您可以尝试在 期间禁用中断或禁用抢占吗udelay?另外,尝试阅读之前和之后的 TSC。

  • [基于 TSC 的延迟代码](http://lxr.linux.no/#linux+v2.6.38/arch/x86/lib/delay.c#L51) 正确地考虑了延迟期间 CPU 之间的转移。TSC 在延迟期间停止只会使延迟*更长*,而不是*更短*,所以这也不是问题。 (2认同)