2011-12-02 10 views
6

Mam sterownik, który wymaga mikrosekundowych opóźnień. Aby utworzyć to opóźnienie, mój sterownik używa funkcji udelay jądra. W szczególności jedno połączenie z udelay (90):Linux Kernel: udelay() zwraca zbyt wcześnie?

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 

Mieliśmy problemy z niezawodnością urządzenia. Po wielu debugowaniu śledziliśmy problem do momentu wznowienia pracy sterownika przed upływem 90 sekund. (Zobacz "dowód" poniżej.)

Używam wersji jądra 2.6.38-11-generic SMP (Kubuntu 11.04, x86_64) na Intel Pentium Dual Core (E5700).

O ile mi wiadomo, dokumentacja stwierdza, że ​​udelay opóźni wykonanie dla co najmniej określonego opóźnienia i jest nieprzerwane. Czy jest jakiś błąd w tej wersji jądra, czy też źle zrozumiałem coś o korzystaniu z udelay?


Aby przekonać się, że problem został spowodowany przez udelay powrocie zbyt wcześnie, karmione zegar 100kHz do jednego z portów I/O i wdrożony własny opóźnienia w następujący sposób:

// 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 sterownik działa teraz bezbłędnie.


W końcowej nocie, znalazłem a discussion wskazując, że skalowanie częstotliwości może być przyczyną opóźnienia *() Rodzina funkcji źle się zachowywać, ale to było na liście mailingowej ARM - I zakładając, że takie problemy byłoby nie- istnieje na komputerze z systemem Linux x86.

Odpowiedz

2

Urządzenie E5700 ma X86_FEATURE_CONSTANT_TSC, ale nie X86_FEATURE_NONSTOP_TSC. TSC jest prawdopodobnym źródłem zegara dla udelay. Dopóki nie zostanie powiązany z jednym z rdzeni z maską koligacji, twoje zadanie mogło zostać zmienione i przeniesione na inny procesor podczas udelay. Lub TSC może nie być stabilny w trybach CPU o mniejszej mocy.

Czy można spróbować wyłączyć przerywające lub wyłączające prewencję podczas udelay? Spróbuj także przeczytać TSC przed i po.

+0

Spróbuję i skontaktuję się z Tobą. Po prostu rozumiem, że masz rację, każdy rdzeń ma swój własny TSC, więc jeśli proces, który mój sterownik obsługuje, został przełożony na inny procesor, TSC może nie być taki sam? Czy rozumiem poprawnie, że X86_FEATURE_CONSTANT_TSC oznacza, że ​​TSC procesora jest stabilne, niezależnie od skalowania częstotliwości, a X86_FEATURE_NONSTOP_TSC oznacza, że ​​TSC nigdy nie przestanie liczyć? Jeśli tak, to kiedy procesor zatrzymałby się, to TSC? –

+0

TSC może zatrzymać się podczas niektórych [C-stanów] (http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Processor_states). –

+2

Kod opóźnienia oparty na TSC (http://lxr.linux.no/#linux+v2.6.38/arch/x86/lib/delay.c#L51) poprawnie uwzględnia przesunięcie między procesorami podczas opóźnienia. Zatrzymanie TSC w czasie opóźnienia spowodowałoby tylko, że opóźnienie * będzie dłuższe *, a nie * krótsze *, więc nie stanowi to problemu. – caf

3

Nie znam żadnego błędu w tej wersji jądra (ale to nie znaczy, że go nie ma).

udelay() nie jest "bezprzerwowy" - nie wyłącza przedawnienia, więc twoje zadanie może zostać wywłaszczone przez zadanie RT w czasie opóźnienia. Jednak to samo dotyczy implementacji alternatywnego opóźnienia, więc jest to mało prawdopodobne.

Czy twoim problemem może być problem z koherencją/pamięcią DMA? Twoja alternatywna implementacja opóźnienia uzyskuje dostęp do magistrali, więc może to ukrywać prawdziwy problem jako efekt uboczny.

+0

Przepraszam, rozumiem przez "uninterruptible", że połączenie powinno wrócić dopiero po upływie opóźnienia. W tym sterowniku nie używam DMA. W przypadku problemów z koherencją pamięci podręcznej urządzeniem jest układ FPGA PCI-Express. Podczas sondowania urządzenia, żądam jego regionu I/O i używam ioremap_nocache(), aby uzyskać adres bazowy używany we wszystkich funkcjach I/O. Myślałem, że używanie ioremap_nocache() zapewnia spójność pamięci podręcznej? –

Powiązane problemy