6

マイクロ秒の遅延が必要なドライバーがあります。この遅延を作成するために、ドライバーはカーネルの udelay 関数を使用しています。具体的には、udelay(90) への呼び出しが 1 つあります。

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 が経過する前にドライバーが再開する問題を突き止めました。(以下の「証明」を参照してください。)

Intel Pentium Dual Core (E5700) でカーネル バージョン 2.6.38-11-generic SMP (Kubuntu 11.04、x86_64) を実行しています。

私の知る限り、ドキュメントには、udelay は少なくとも指定された遅延の実行を遅らせ、中断できないと記載されています。このバージョンのカーネルにはバグがありますか、それとも udelay の使用について何か誤解していましたか?


問題の原因が udelay の戻りが早すぎることであると確信するために、I/O ポートの 1 つに 100kHz のクロックを供給し、次のように独自の遅延を実装しました。

// 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 ベースではそのような問題は存在しないと思いますパソコン。

4

2 に答える 2

3

そのバージョンのカーネルにバグがあるかどうかはわかりません (ただし、バグがないわけではありません)。

udelay()「割り込み不可」ではありません-プリエンプションを無効にしないため、遅延中にRTタスクによってタスクがプリエンプトされる可能性があります。ただし、代替遅延の実装についても同じことが当てはまるため、問題になる可能性はほとんどありません。

あなたの実際の問題は、DMA コヒーレンシ/メモリ順序の問題でしょうか? 代替遅延の実装はバスにアクセスするため、これが実際の問題を副作用として隠している可能性があります。

于 2011-12-05T04:20:30.277 に答える
2

E5700にはありますX86_FEATURE_CONSTANT_TSCが、ありませんX86_FEATURE_NONSTOP_TSC。TSCは、のクロックソースである可能性がありudelayます。アフィニティマスクでコアの1つにバインドされていない限り、タスクがプリエンプションされ、の間に別のCPUに再スケジュールされた可能性がありますudelay。または、低電力CPUモードではTSCが安定しない場合があります。

割り込みを無効にしたり、プリエンプションを無効にしたりできますudelayか?また、前後にTSCを読んでみてください。

于 2011-12-03T03:10:13.773 に答える