У меня есть драйвер, который требует микросекундных задержек. Чтобы создать эту задержку, мой драйвер использует функцию ядра udelay. В частности, там это один вызов 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
У нас были проблемы с надежностью устройства. После долгой отладки мы отследили проблему до возобновления работы драйвера до того, как прошло 90 мкс (см. «доказательство» ниже.)
Я использую ядро версии 2.6.38-11-generic SMP (Kubuntu 11.04, x86_64) на Intel Pentium Dual Core (E5700).
Насколько мне известно, в документации указано, что udelay будет задерживать выполнение на по крайней мере на указанную задержку и является бесперебойным. Есть ли ошибка в этой версии ядра, или я неправильно понял использование udelay?
Чтобы убедить себя, что проблема вызвана слишком ранним возвратом udelay, мы подали частоту 100 кГц на один из порты ввода-вывода и реализовали нашу собственную задержку следующим образом:
// 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;
}
}
}
}
... и драйвер теперь работает безупречно.
В качестве последнего примечания, я обнаружил обсуждение , указывающее на то, что масштабирование частоты могло приводить к неправильному функционированию семейства функций * delay (), но это было в списке рассылки ARM - я предполагал, что такие проблемы будут не существовать на ПК на базе Linux x86.