2011-12-02 92 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()確保緩存一致性? –