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