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

时间:2011-12-02 07:00:52

标签: 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

我们遇到了设备的可靠性问题。经过大量的调试,我们在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;
            }
        }
    }
}

......司机现在可以完美运作。


作为最后一点,我发现a discussion表示频率缩放可能导致* delay()系列函数行为异常,但这是在ARM邮件列表上 - 我假设这些问题是非存在于基于Linux x86的PC上。

2 个答案:

答案 0 :(得分:3)

我不知道该版本的内核有任何错误(但这并不意味着没有错误)。

udelay()不是“不可中断的” - 它不会禁用抢占,因此您的任务可以在延迟期间被RT任务抢占。但是,您的备用延迟实现也是如此,因此不太可能出现问题。

您的实际问题可能是DMA一致性/内存排序问题吗?您的备用延迟实现会访问总线,因此这可能会将实际问题隐藏为副作用。

答案 1 :(得分:2)

E5700有X86_FEATURE_CONSTANT_TSC但不是X86_FEATURE_NONSTOP_TSC。 TSC可能是udelay的时钟源。除非使用关联掩码绑定到其中一个核心,否则在udelay期间,您的任务可能已被抢占并重新安排到另一个CPU。或者在低功耗CPU模式下TSC可能不稳定。

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