Kernel Linux: udelay () retorna muito cedo?
Tenho um driver que requer atrasos de microssegundos. Para criar esse atraso, meu driver está usando a função udelay do kernel. Especificamente, há uma chamada para udelay (90):
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
Tivemos problemas de confiabilidade com o dispositivo. Depois de muita depuração, rastreamos o problema até o driver reiniciar antes dos 90us terem passado. (Veja "prova" abaixo.)
Estou executando o SMP da versão 2.6.38-11 genérica do kernel (Kubuntu 11.04, x86_64) em um Intel Pentium Dual Core (E5700
Até onde eu sei, a documentação afirma que o udelay atrasará a execução definalment o atraso especificado e é ininterrupto. Existe algum bug nesta versão do kernel, ou eu entendi algo errado sobre o uso do udela
Para nos convencermos de que o problema foi causado pelo retorno do udelay muito cedo, alimentamos um relógio de 100kHz em uma das portas de E / S e implementamos nosso próprio atraso da seguinte maneira:
// 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;
}
}
}
}
... e o motorista agora funciona perfeitament
Como nota final, acheiuma discussã indicando que o escalonamento de frequência pode estar causando um comportamento inadequado à família de funções * delay (), mas isso estava em uma lista de discussão do ARM - presumindo que tais problemas não existissem em um PC com Linux x8