2011-12-02 86 views
6

我有一个需要微秒延迟的驱动程序。为了创建这个延迟,我的驱动程序正在使用内核的udelay函数。具体而言,有一个呼叫udelay的(90):Linux内核:udelay()返回得太早?

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奔腾双核(E5700)上运行内核版本2.6.38-11-通用SMP(Kubuntu 11.04,x86_64)。

据我所知,文档指出udelay的将推迟至少指定的延迟执行,并且是不间断。 这个版本的内核有bug吗,还是误解了udelay的使用?


要说服自己,认为该问题是由udelay的返回太早造成的,我们给100kHz的时钟的I/O端口之一,并实现了自己的延迟如下:

// 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表明频率缩放可能会造成功能无法正常运作的*延迟()系列,但这是一个ARM邮件列表上 - 我假设这样的问题将是不可存在于基于Linux x86的PC上。

回答

2

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

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

+0

我会尝试一下并回复你。我的理解是正确的,每个核心都有自己的TSC,所以如果我的驱动程序正在维修的过程被重新调度到另一个CPU,那么TSC可能会不一样? 另外,我是否正确理解X86_FEATURE_CONSTANT_TSC表示CPU的TSC稳定,无论频率调整如何,X86_FEATURE_NONSTOP_TSC意味着TSC将永不停止计数?如果是这样,CPU何时会暂停TSC? –

+0

TSC可能会在特定[C-States]期间停机(http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Processor_states)。 –

+2

在延迟期间[基于TSC的延迟代码](http://lxr.linux.no/#linux+v2.6.38/arch/x86/lib/delay.c#L51)正确说明在CPU之间发生了移位。 TSC在延迟期间停止会使延迟更长*,而不是更短*,所以这也不是问题。 – caf

3

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

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

您的实际问题可能是DMA一致性/内存排序问题吗?您的备用延迟实施访问公共汽车,因此这可能隐藏真正的问题作为副作用。

+0

对不起,我所说的“不可中断”的意思是,只有在延迟结束后才能返回呼叫。 在这个驱动程序中,我没有使用DMA。 至于缓存一致性问题,该设备是一个PCI-Express FPGA。在探测设备时,我要求它是I/O区域,并使用ioremap_nocache()来获取所有I/O功能中使用的基地址。我认为使用ioremap_nocache()确保缓存一致性? –