2011-12-02 18 views
6

Mikro saniye gecikmeleri gerektiren bir sürücüm var. Bu gecikmeyi oluşturmak için, sürücüm kernel'in udelay işlevini kullanıyor. Özel olarak, udelay (90) için bir çağrı var. Aygıtla ilgili güvenilirlik sorunlarımız vardı. Çok fazla hata ayıklamasından sonra, 90us'un geçmesinden önce sürücünün devam etmesini sağladık. (Aşağıdaki "prova" bölümüne bakın.)Linux Çekirdek: udelay() çok erken geri döndü mü?

Intel Pentium Dual Core (E5700) üzerinde çekirdek sürümü 2.6.38-11-jenerik SMP (Kubuntu 11.04, x86_64) çalıştırıyorum.

Bildiğim kadarıyla, dokümanlar udelay'in belirtilen gecikmeyi en az yürütmeyi geciktireceğini ve kesintisiz olduğunu belirtir. Çekirdeğin bu sürümünde bir hata var mı, yoksa udelay kullanımıyla ilgili bir şeyi yanlış anlamış mıyım? aşağıdaki gibi sorun udelay çok erken dönen neden olduğunu kendimizi ikna etmek


, biz I/O bağlantı noktalarından birine bir 100kHz saati beslenen ve kendi gecikme uygulanan:

// 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; 
      } 
     } 
    } 
} 

... ve sürücü şimdi kusursuz çalışıyor. Son bir not


, o frekans ölçekleme yaramazlık fonksiyonların * gecikme() ailesini neden olabilecek belirten a discussion bulundu, ancak bu bir ARM posta listesinde - ben gibi sorunları varsayarak olmayan olacağını Linux x86 tabanlı bir bilgisayarda var.

cevap

2

E5700'ün X86_FEATURE_CONSTANT_TSC vardır, ancak X86_FEATURE_NONSTOP_TSC değil. TSC, udelay için muhtemel saat kaynağıdır. Bir yakınlık maskesine sahip çekirdeklerden birine bağlı olmadıkça, göreviniz udelay sırasında başka bir CPU'ya önceden yeniden ayarlanmış ve yeniden planlanmış olabilir. Ya da düşük güçte çalışan CPU modlarında TSC sabit olmayabilir.

udelay sırasında kesintileri devre dışı bırakmayı veya önlenmeyi devre dışı bırakmayı deneyebilir misiniz? Ayrıca, önce ve sonra TSC'yi okumayı deneyin.

+0

Denerim ve size geri döneceğim. Sadece sizi doğru anlıyorum, her çekirdeğin kendi TSC'si var, bu yüzden eğer şoförün bakım yaptığı işlem başka bir CPU'ya yeniden ayarlanmışsa, TSC aynı olmayabilir mi? Ayrıca, X86_FEATURE_CONSTANT_TSC'nin, CPU'nun TSC'sinin frekans ölçeklemesinden bağımsız olarak kararlı olduğunu ve X86_FEATURE_NONSTOP_TSC'nin TSC'nin asla saymayı durduracağı anlamına geldiğini doğru bir şekilde anlıyor musunuz? Eğer öyleyse, bir CPU ne zaman TSC'yi durdurur? –

+0

TSC, belirli [C-States] (http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Processor_states) sırasında durdurabilir. –

+2

[TSC tabanlı gecikme kodu] (http://lxr.linux.no/#linux+v2.6.38/arch/x86/lib/delay.c#L51), gecikmeler sırasında CPU'lar arasında kaydırılmayı uygun şekilde hesaplar. Gecikme sırasında TSC'nin durması sadece gecikmeyi * daha uzun *, daha * kısa * yapar, bu da sorun değildir. – caf

3

Çekirdeğin bu sürümünde herhangi bir hata bilmiyorum (ancak bu bir tane olmadığı anlamına gelmez).

udelay() "kesintisiz" değil - önleme işlemini devre dışı bırakmaz, böylece göreviniz gecikme sırasında bir RT görevi tarafından engellenebilir. Ancak aynı durum alternatif gecikme uygulamanız için de geçerlidir, bu nedenle sorun olması olası değildir.

Gerçek sorununuz bir DMA tutarlılığı/bellek siparişi sorunu olabilir mi? Alternatif gecikme uygulamanız otobüse erişir, bu yüzden asıl sorunu bir yan etki olarak gizleyebilir.

+0

Maalesef, "kesintisiz" ile kastedilen, çağrının yalnızca gecikme bittiğinde geri dönmesi gerektiğiydi. Bu sürücüde DMA kullanmıyorum. Önbellek tutarlılığı sorunları için, cihaz bir PCI-Express FPGA'dır. Aygıtı araştırırken, I/O bölgesini talep ediyorum ve tüm G/Ç işlevlerinde kullanılan temel adresi almak için ioremap_nocache() yöntemini kullanın. Ioremap_nocache() kullanarak önbellek tutarlılığı sağlar düşündüm? –

İlgili konular