У меня есть драйвер, который требует микросекундных задержек. Чтобы создать эту задержку, мой драйвер использует функцию ядра 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
У нас были проблемы с надежностью устройства. После долгих отладок мы отследили проблему до возобновления драйвера до 90us. (См. «Доказательство» ниже.)
Я использую ядро версии 2.6.38-11 - общий SMP (Kubuntu 11.04, x86_64) на двухъядерном процессоре Intel Pentium (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.